sequelizer.js 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235
  1. // ███████╗███████╗ ██████╗ ██╗ ██╗███████╗██╗ ██╗███████╗███████╗██████╗
  2. // ██╔════╝██╔════╝██╔═══██╗██║ ██║██╔════╝██║ ██║╚══███╔╝██╔════╝██╔══██╗
  3. // ███████╗█████╗ ██║ ██║██║ ██║█████╗ ██║ ██║ ███╔╝ █████╗ ██████╔╝
  4. // ╚════██║██╔══╝ ██║▄▄ ██║██║ ██║██╔══╝ ██║ ██║ ███╔╝ ██╔══╝ ██╔══██╗
  5. // ███████║███████╗╚██████╔╝╚██████╔╝███████╗███████╗██║███████╗███████╗██║ ██║
  6. // ╚══════╝╚══════╝ ╚══▀▀═╝ ╚═════╝ ╚══════╝╚══════╝╚═╝╚══════╝╚══════╝╚═╝ ╚═╝
  7. //
  8. // Uses Knex to generate a SQL query for a given token tree. Tokens are produced
  9. // by running them through the tokenizer.
  10. var _ = require('@sailshq/lodash');
  11. module.exports = function sequelizer(options) {
  12. var knex = options.knex;
  13. var tree = options.tree;
  14. if (!knex) {
  15. throw new Error('Missing Knex instance. Options must contain both `knex` and `tree` values.');
  16. }
  17. if (!tree) {
  18. throw new Error('Missing tree dictionary. Options must contain both `knex` and `tree` values.');
  19. }
  20. // Lodash 3.10 version of _.fromPairs from Lodash 4.0
  21. var fromPairs = function fromPairs(pairs) {
  22. var index = -1;
  23. var length = pairs ? pairs.length : 0;
  24. var result = {};
  25. while (++index < length) {
  26. var pair = pairs[index];
  27. result[pair[0]] = pair[1];
  28. }
  29. return result;
  30. };
  31. // ╔╗ ╦ ╦╦╦ ╔╦╗ ╔═╗ ╦ ╦╔═╗╦═╗╦ ╦ ╔═╗╦╔═╗╔═╗╔═╗
  32. // ╠╩╗║ ║║║ ║║ ║═╬╗║ ║║╣ ╠╦╝╚╦╝ ╠═╝║║╣ ║ ║╣
  33. // ╚═╝╚═╝╩╩═╝═╩╝ ╚═╝╚╚═╝╚═╝╩╚═ ╩ ╩ ╩╚═╝╚═╝╚═╝
  34. //
  35. // Applys a function to the Knex query builder.
  36. var buildQueryPiece = function buildQueryPiece(fn, expression, query) {
  37. // Ensure the value is always an array
  38. if (!_.isArray(expression)) {
  39. expression = [expression];
  40. }
  41. query[fn].apply(query, expression);
  42. };
  43. // ╔═╗╦ ╦╔═╗╔═╗╦╔═ ╔═╗╔═╗╦═╗ ╔╦╗╔═╗╔╦╗╦╔═╗╦╔═╗╦═╗╔═╗
  44. // ║ ╠═╣║╣ ║ ╠╩╗ ╠╣ ║ ║╠╦╝ ║║║║ ║ ║║║╠╣ ║║╣ ╠╦╝╚═╗
  45. // ╚═╝╩ ╩╚═╝╚═╝╩ ╩ ╚ ╚═╝╩╚═ ╩ ╩╚═╝═╩╝╩╚ ╩╚═╝╩╚═╚═╝
  46. //
  47. // Check for any embedded combinators (OR) or modifiers (NOT) in a single
  48. // expression set.
  49. var checkForModifiers = function checkForModifiers(expr, options) {
  50. var combinator;
  51. var modifiers = [];
  52. // Default to removing the values from the array
  53. options = options || {};
  54. options = _.defaults(options, { strip: true });
  55. // Normalize strip attibutes
  56. if (options.strip === true) {
  57. options.strip = '*';
  58. }
  59. // Check for any encoded combinators and remove them
  60. (function checkForAnd() {
  61. var cIdx = _.indexOf(expr, 'AND');
  62. if (cIdx > -1) {
  63. combinator = 'AND';
  64. if (options.strip && (options.strip === '*' || _.indexOf(options.strip, 'AND') > -1)) {
  65. _.pullAt(expr, cIdx);
  66. }
  67. }
  68. })();
  69. (function checkForOr() {
  70. var cIdx = _.indexOf(expr, 'OR');
  71. if (cIdx > -1) {
  72. combinator = 'OR';
  73. if (options.strip && (options.strip === '*' || _.indexOf(options.strip, 'OR') > -1)) {
  74. _.pullAt(expr, cIdx);
  75. }
  76. }
  77. })();
  78. // Check for any modifiers added to the beginning of the expression.
  79. // These represent things like NOT. Pull the value from the expression
  80. (function checkForNot() {
  81. var mIdx = _.indexOf(expr, 'NOT');
  82. if (mIdx > -1) {
  83. modifiers.push('NOT');
  84. if (options.strip && (options.strip === '*' || _.indexOf(options.strip, 'NOT') > -1)) {
  85. _.pullAt(expr, mIdx);
  86. }
  87. }
  88. })();
  89. (function checkForIn() {
  90. var mIdx = _.indexOf(expr, 'IN');
  91. if (mIdx > -1) {
  92. modifiers.push('IN');
  93. if (options.strip && (options.strip === '*' || _.indexOf(options.strip, 'IN') > -1)) {
  94. _.pullAt(expr, mIdx);
  95. }
  96. }
  97. })();
  98. (function checkForNotIn() {
  99. var mIdx = _.indexOf(expr, 'NOTIN');
  100. if (mIdx > -1) {
  101. modifiers.push('NOTIN');
  102. if (options.strip && (options.strip === '*' || _.indexOf(options.strip, 'NOTIN') > -1)) {
  103. _.pullAt(expr, mIdx);
  104. }
  105. }
  106. })();
  107. return {
  108. combinator: combinator,
  109. modifier: modifiers
  110. };
  111. };
  112. // ╔╗ ╦ ╦╦╦ ╔╦╗ ╦╔═╔╗╔╔═╗═╗ ╦
  113. // ╠╩╗║ ║║║ ║║ ╠╩╗║║║║╣ ╔╩╦╝
  114. // ╚═╝╚═╝╩╩═╝═╩╝ ╩ ╩╝╚╝╚═╝╩ ╚═
  115. // ╔═╗╦═╗╔═╗╦ ╦╔═╗╦╔╗╔╔═╗ ╔═╗╦ ╦╔╗╔╔═╗╔╦╗╦╔═╗╔╗╔
  116. // ║ ╦╠╦╝║ ║║ ║╠═╝║║║║║ ╦ ╠╣ ║ ║║║║║ ║ ║║ ║║║║
  117. // ╚═╝╩╚═╚═╝╚═╝╩ ╩╝╚╝╚═╝ ╚ ╚═╝╝╚╝╚═╝ ╩ ╩╚═╝╝╚╝
  118. //
  119. // Given a set of expressions, create a Knex grouping statement.
  120. // ex:
  121. // query.whereNot(function() {
  122. // this.where('id', 1).orWhereNot('id', '>', 10)
  123. // })
  124. //
  125. // This is probably the piece that needs the most work. I would really like
  126. // to have the parent function figured out before it get's here so I don't
  127. // need to mess around with all this modifiers stuff so much. It feels
  128. // very brittle.
  129. var buildKnexGroupingFn = function buildKnexGroupingFn(expressionGroup, modifier, query) {
  130. // Create a new "copy" of the expression group to use in the closure.
  131. var _exprGroup = _.merge([], expressionGroup);
  132. expressionGroup = [];
  133. // Default the fn value to `orWhere` unless an AND modifier was
  134. // specifically set
  135. var fn = 'orWhere';
  136. if (modifier && _.isArray(modifier) && _.first(modifier) === 'AND') {
  137. fn = 'andWhere';
  138. }
  139. // Build a function that when called, creates a nested grouping of statements.
  140. query[fn].call(query, function buildGroupFn() {
  141. var self = this;
  142. // ╔╦╗╔═╗╔╦╗╔═╗╦═╗╔╦╗╦╔╗╔╔═╗ ┬┌─┌┐┌┌─┐─┐ ┬ ┌─┐┬ ┬┌┐┌┌─┐┌┬┐┬┌─┐┌┐┌
  143. // ║║║╣ ║ ║╣ ╠╦╝║║║║║║║║╣ ├┴┐│││├┤ ┌┴┬┘ ├┤ │ │││││ │ ││ ││││
  144. // ═╩╝╚═╝ ╩ ╚═╝╩╚═╩ ╩╩╝╚╝╚═╝ ┴ ┴┘└┘└─┘┴ └─ └ └─┘┘└┘└─┘ ┴ ┴└─┘┘└┘
  145. var determineFn = function determineFn(_expr, idx) {
  146. // default the _fn to `orWhere`
  147. var _fn = 'orWhere';
  148. // Check for any modifiers and combinators in this expression piece
  149. var modifiers = checkForModifiers(_expr, {
  150. strip: ['NOT', 'AND', 'OR', 'IN', 'NOTIN']
  151. });
  152. // Check the modifier to see what fn to use
  153. if (modifiers.modifier.length) {
  154. if (modifiers.modifier.length === 1) {
  155. if (_.first(modifiers.modifier) === 'NOT') {
  156. // Handle WHERE NOT
  157. if (modifiers.combinator === 'AND') {
  158. _fn = 'whereNot';
  159. }
  160. // Defaults to OR when grouping
  161. if (modifiers.combinator === 'OR' || !modifiers.combinator) {
  162. _fn = 'orWhereNot';
  163. modifiers.combinator = 'OR';
  164. }
  165. }
  166. else if (_.first(modifiers.modifier) === 'NOTIN') {
  167. _fn = 'whereNotIn';
  168. }
  169. else if (_.first(modifiers.modifier) === 'IN') {
  170. if (modifiers.combinator === 'AND') {
  171. _fn = 'whereIn';
  172. } else {
  173. _fn = 'orWhereIn';
  174. modifiers.combinator = 'OR';
  175. }
  176. }
  177. }
  178. // If we end up with something like [AND, NOT, IN].
  179. // Throw out the AND.
  180. if (modifiers.modifier.length > 1) {
  181. if (_.first(modifiers.modifier) === 'AND') {
  182. _.pullAt(modifiers.modifier, 0);
  183. }
  184. var first = _.first(_.pullAt(modifiers.modifier, 0));
  185. var second = _.first(_.pullAt(modifiers.modifier, 0));
  186. if (first === 'NOT' && second === 'IN') {
  187. _fn = 'orWhereNotIn';
  188. }
  189. }
  190. // Handle empty modifiers. Use this when not negating. Defaulting to
  191. // use the `orWhere` statement already set.
  192. } else {
  193. if (modifiers.combinator === 'AND') {
  194. _fn = 'andWhere';
  195. }
  196. if (modifiers.combinator === 'OR') {
  197. _fn = 'orWhere';
  198. }
  199. }
  200. // If the first item in the array, always force the fn to be
  201. // where or whereIn or whereNotIn. This is part of the way Knex works.
  202. if (idx === 0) {
  203. if (_fn === 'orWhereNotIn') {
  204. _fn = 'whereNotIn';
  205. } else if (_fn === 'whereIn' || _fn === 'orWhereIn') {
  206. _fn = 'whereIn';
  207. } else if (_fn === 'orWhereNot') {
  208. _fn = 'whereNot';
  209. } else if (_fn === 'whereNotIn') {
  210. _fn = 'whereNotIn';
  211. } else if (_fn === 'whereNotNull') {
  212. _fn = 'whereNotNull';
  213. } else {
  214. _fn = 'where';
  215. }
  216. }
  217. return _fn;
  218. };
  219. // ╦═╗╔═╗╔═╗╦ ╦╦═╗╔═╗╔═╗ ┌┬┐┬ ┬┬─┐┌─┐┬ ┬┌─┐┬ ┬ ┌─┐┬─┐┌─┐┬ ┬┌─┐┌─┐
  220. // ╠╦╝║╣ ║ ║ ║╠╦╝╚═╗║╣ │ ├─┤├┬┘│ ││ ││ ┬├─┤ │ ┬├┬┘│ ││ │├─┘└─┐
  221. // ╩╚═╚═╝╚═╝╚═╝╩╚═╚═╝╚═╝ ┴ ┴ ┴┴└─└─┘└─┘└─┘┴ ┴ └─┘┴└─└─┘└─┘┴ └─┘
  222. var recurse = function recurse(localExpr) {
  223. // If the localExpression is made up of multiple items keep going building
  224. // functions along the way.
  225. if (_.isArray(localExpr) && localExpr.length && _.isArray(_.first(localExpr))) {
  226. return [function nestedFn() {
  227. // Use self here to reference the Knex calling context
  228. var self = this;
  229. // Apply each expression in the set as a knex function
  230. _.each(localExpr, function applyArgs(expressionSet, idx) {
  231. var _fn = determineFn(expressionSet, idx);
  232. var args = recurse(expressionSet);
  233. self[_fn].apply(self, args);
  234. });
  235. }];
  236. }
  237. return localExpr;
  238. };
  239. // ╦╔═╦╔═╗╦╔═ ┌─┐┌─┐┌─┐ ┬─┐┌─┐┌─┐┬ ┬┬─┐┌─┐┬┌─┐┌┐┌
  240. // ╠╩╗║║ ╠╩╗ │ │├┤ ├┤ ├┬┘├┤ │ │ │├┬┘└─┐││ ││││
  241. // ╩ ╩╩╚═╝╩ ╩ └─┘└ └ ┴└─└─┘└─┘└─┘┴└─└─┘┴└─┘┘└┘
  242. _.each(_exprGroup, function processGroups(_expr, idx) {
  243. var _fn = determineFn(_expr, idx);
  244. var args = recurse(_expr);
  245. // Be sure to always remove any extra NOT or NOT in arguments
  246. if (_.indexOf(['NOT', 'NOTIN'], _.first(args)) > -1) {
  247. _.pullAt(args, 0);
  248. }
  249. // Apply the knex function
  250. self[_fn].apply(self, args);
  251. });
  252. });
  253. };
  254. // ╦ ╦╦ ╦╔═╗╦═╗╔═╗ ╔═╗═╗ ╦╔═╗╦═╗╔═╗╔═╗╔═╗╦╔═╗╔╗╔ ╔╗ ╦ ╦╦╦ ╔╦╗╔═╗╦═╗
  255. // ║║║╠═╣║╣ ╠╦╝║╣ ║╣ ╔╩╦╝╠═╝╠╦╝║╣ ╚═╗╚═╗║║ ║║║║ ╠╩╗║ ║║║ ║║║╣ ╠╦╝
  256. // ╚╩╝╩ ╩╚═╝╩╚═╚═╝ ╚═╝╩ ╚═╩ ╩╚═╚═╝╚═╝╚═╝╩╚═╝╝╚╝ ╚═╝╚═╝╩╩═╝═╩╝╚═╝╩╚═
  257. //
  258. // Builds up an array of values that can be passed into the .where or .orWhere
  259. // functions of Knex.
  260. var whereBuilder = function whereBuilder(expr, expression, modifier) {
  261. // Handle KEY/VALUE pairs
  262. if (expr.type === 'KEY') {
  263. // Reset the expression for each new key, unless there was already a
  264. // modifier present.
  265. expression = expression.length > 1 ? [] : expression;
  266. expression.push(expr.value);
  267. return expression;
  268. }
  269. // Handle OPERATORS such as '>' and '<'
  270. if (expr.type === 'OPERATOR') {
  271. expression.push(expr.value);
  272. return expression;
  273. }
  274. // Set the value
  275. if (expr.type === 'VALUE') {
  276. if (expr.value === null && _.last(expression) === '!=') {
  277. modifier = modifier || [];
  278. modifier.push('NOT');
  279. }
  280. expression.push(expr.value);
  281. return expression;
  282. }
  283. };
  284. // ╔═╗╦═╗╔═╗╔═╗╔═╗╔═╗╔═╗ ╔═╗╔═╗╔╗╔╔╦╗╦╔╦╗╦╔═╗╔╗╔╔═╗╦
  285. // ╠═╝╠╦╝║ ║║ ║╣ ╚═╗╚═╗ ║ ║ ║║║║ ║║║ ║ ║║ ║║║║╠═╣║
  286. // ╩ ╩╚═╚═╝╚═╝╚═╝╚═╝╚═╝ ╚═╝╚═╝╝╚╝═╩╝╩ ╩ ╩╚═╝╝╚╝╩ ╩╩═╝
  287. // ╔═╗╦═╗╔═╗╦ ╦╔═╗╦╔╗╔╔═╗ ╔═╗╔╦╗╔═╗╔╦╗╔╦╗╔═╗╔╗╔╔╦╗
  288. // ║ ╦╠╦╝║ ║║ ║╠═╝║║║║║ ╦ ╚═╗ ║ ╠═╣ ║ ║║║║╣ ║║║ ║
  289. // ╚═╝╩╚═╚═╝╚═╝╩ ╩╝╚╝╚═╝ ╚═╝ ╩ ╩ ╩ ╩ ╩ ╩╚═╝╝╚╝ ╩
  290. //
  291. // Conditional statements are grouped into sets. This function processes
  292. // the tokens in a single one of those sets.
  293. var processConditionalSet = function processConditionalSet(tokens, nested, expression, modifier, query) {
  294. // Hold values that make up a nested expression group.
  295. var expressionGroup = [];
  296. // Hold a flag to determine if a subquery is being used inside the conditional.
  297. var subQuery = false;
  298. var currentCombinator;
  299. // Loop through each expression in the group
  300. _.each(tokens, function processSet(groupedExpr) {
  301. // If there is a NOT condition, add the NOT condition as the first item
  302. // in the expression.
  303. if (groupedExpr.type === 'CONDITION' && groupedExpr.value === 'NOT') {
  304. expression.unshift(groupedExpr.value);
  305. currentCombinator = 'NOT';
  306. return;
  307. }
  308. // If there is a IN condition, add the condition as the first item in
  309. // the expression.
  310. if (groupedExpr.type === 'CONDITION' && groupedExpr.value === 'IN') {
  311. expression.unshift(groupedExpr.value);
  312. currentCombinator = 'IN';
  313. return;
  314. }
  315. // If there is a NOTIN condition, add the condition as the first item in
  316. // the expression.
  317. if (groupedExpr.type === 'CONDITION' && groupedExpr.value === 'NOTIN') {
  318. expression.unshift(groupedExpr.value);
  319. currentCombinator = 'NOTIN';
  320. return;
  321. }
  322. // If there is a AND condition, add the condition as the first item in
  323. // the expression.
  324. if (groupedExpr.type === 'CONDITION' && groupedExpr.value === 'AND') {
  325. currentCombinator = 'AND';
  326. return;
  327. }
  328. // If the grouped expression represents a SUBQUERY, process it standalone
  329. // and then add it to the expression group.
  330. if (_.isArray(groupedExpr) && subQuery) {
  331. // Build a standalone knex query builder and pass it the grouped expression
  332. var subQueryBuilder = knex.queryBuilder();
  333. tokenParser(subQueryBuilder, groupedExpr);
  334. // Toggle off the subquery flag
  335. subQuery = false;
  336. // Add the subQueryBuilder instance to the expression
  337. expression.push(subQueryBuilder);
  338. // Add the expression to the expression group
  339. expressionGroup.push(expression);
  340. return;
  341. }
  342. // If the grouped expression is a nested array, this represents a nested
  343. // OR statement. So instead of building the query outright, we want to
  344. // collect all the pieces that make it up and call the Knex grouping
  345. // function at the end.
  346. if (_.isArray(groupedExpr)) {
  347. (function groupExpression() {
  348. var groupedExpression = processGroup(groupedExpr, true, expression, modifier, query);
  349. // Add the combinator to the beginning so that further processing knows
  350. // which context the expression should be used in. For example OR vs AND
  351. if (_.indexOf(['OR', 'AND', 'NOT', 'NOTIN'], _.first(groupedExpression)) < 0) {
  352. if (currentCombinator) {
  353. groupedExpression.unshift(currentCombinator);
  354. } else {
  355. groupedExpression.unshift('OR');
  356. currentCombinator = undefined;
  357. }
  358. }
  359. expressionGroup.push(groupedExpression);
  360. })();
  361. return;
  362. }
  363. // If there is a SUBQUERY, process it standalone and then set it as the
  364. // value in the expression
  365. if (groupedExpr.type === 'SUBQUERY') {
  366. subQuery = true;
  367. return;
  368. }
  369. // If there is a KEY/OPERATOR/VALUE token, process it using the where builder
  370. if (groupedExpr.type === 'KEY' || groupedExpr.type === 'OPERATOR' || groupedExpr.type === 'VALUE') {
  371. expression = whereBuilder(groupedExpr, expression);
  372. }
  373. // If the expression's type is value after we are done processing it we
  374. // can add it to the query. Unless we are in a nested statement in
  375. // which case just add it to the expression group.
  376. if (groupedExpr.type === 'VALUE') {
  377. // Look ahead in the tokens and see if there are any more VALUE
  378. // expressions. If so, this will need to be an expression group so
  379. // that we get parenthesis around it. This is commonly used where you
  380. // have a criteria like the following:
  381. // {
  382. // or: [
  383. // { name: 'foo' },
  384. // { age: 21, username: 'bar' }
  385. // ]
  386. // }
  387. // Here we need to wrap the `age` and `username` part of the
  388. // expression in parenthesis.
  389. var hasMoreValues = _.filter(tokens, { type: 'VALUE' });
  390. // If there are more values, add the current expression to the group.
  391. // Prepend an AND statement to the beginning to show that the will
  392. // end up as (age = 21 and username = bar). If this was an OR statement
  393. // it would be processed differently because the tokens would be
  394. // nested arrays.
  395. if (hasMoreValues.length > 1) {
  396. expression.unshift('AND');
  397. expressionGroup.push(expression);
  398. return;
  399. }
  400. // If this is a nested expression, just update the expression group
  401. if (nested) {
  402. expressionGroup = expressionGroup.concat(expression);
  403. return;
  404. }
  405. expressionGroup.push(expression);
  406. }
  407. });
  408. // Return the expression group
  409. return expressionGroup;
  410. };
  411. // ╔═╗╦═╗╔═╗╔═╗╔═╗╔═╗╔═╗ ╔═╗╔═╗╔╗╔╔╦╗╦╔╦╗╦╔═╗╔╗╔╔═╗╦
  412. // ╠═╝╠╦╝║ ║║ ║╣ ╚═╗╚═╗ ║ ║ ║║║║ ║║║ ║ ║║ ║║║║╠═╣║
  413. // ╩ ╩╚═╚═╝╚═╝╚═╝╚═╝╚═╝ ╚═╝╚═╝╝╚╝═╩╝╩ ╩ ╩╚═╝╝╚╝╩ ╩╩═╝
  414. //
  415. // Process a group of values that make up a conditional.
  416. // Such as an OR statement.
  417. var processGroup = function processGroup(tokens, nested, expression, modifier, query) {
  418. // Loop through each expression in the group
  419. var expressionGroup = processConditionalSet(tokens, nested, expression, modifier, query);
  420. // If we are inside of a nested expression, return the group after we are
  421. // done processing all the tokens.
  422. if (nested) {
  423. return expressionGroup;
  424. }
  425. // Now the Knex functions need to be called. We can examine the group and
  426. // if there is only a single item, go ahead and just build a normal Knex
  427. // grouping query.
  428. // ex. query().orWhere([name, 'foo'])
  429. //
  430. // If there are multiple items in the set, we need to create a knex grouping
  431. // function.
  432. if (expressionGroup.length === 1) {
  433. // Check for any modifiers added to the beginning of the expression.
  434. // These represent things like NOT. Pull the value from the expression.
  435. var queryExpression = _.first(expressionGroup);
  436. var modifiers = checkForModifiers(queryExpression);
  437. // Default the fn value to `orWhere` unless an AND modifier was passed in
  438. var fn = 'orWhere';
  439. if (modifier && _.isArray(modifier) && _.first(modifier) === 'AND') {
  440. fn = 'andWhere';
  441. }
  442. // Check if this should be a NOT NULL instead of != null
  443. if (queryExpression.length === 3 && queryExpression[1] === '!=' && _.isNull(queryExpression[2])) {
  444. fn = 'whereNotNull';
  445. queryExpression = [_.first(queryExpression)];
  446. }
  447. // Check the modifier to see if a different function other than
  448. // OR WHERE should be used. The most common is OR WHERE NOT IN.
  449. if (modifiers.modifier.length) {
  450. if (modifiers.modifier.length === 1) {
  451. if (_.first(modifiers.modifier) === 'NOT') {
  452. fn = fn === 'orWhere' ? 'orWhereNot' : 'whereNot';
  453. }
  454. if (_.first(modifiers.modifier) === 'IN') {
  455. fn = fn === 'orWhere' ? 'orWhereIn' : 'whereIn';
  456. }
  457. if (_.first(modifiers.modifier) === 'NOTIN') {
  458. fn = fn === 'orWhere' ? 'orWhereNotIn' : 'whereNotIn';
  459. }
  460. }
  461. }
  462. buildQueryPiece(fn, queryExpression, query);
  463. return;
  464. }
  465. // Otherwise build the grouping function
  466. buildKnexGroupingFn(expressionGroup, modifier, query);
  467. };
  468. // ╔╦╗╔═╗╔╦╗╔═╗╦═╗╔╦╗╦╔╗╔╔═╗ ╦╔═╗╦╔╗╔
  469. // ║║║╣ ║ ║╣ ╠╦╝║║║║║║║║╣ ║║ ║║║║║
  470. // ═╩╝╚═╝ ╩ ╚═╝╩╚═╩ ╩╩╝╚╝╚═╝ ╚╝╚═╝╩╝╚╝
  471. // ╔═╗╦ ╦╔╗╔╔═╗╔╦╗╦╔═╗╔╗╔ ╔═╗╦═╗╔═╗╔╦╗ ╦╔═╔═╗╦ ╦
  472. // ╠╣ ║ ║║║║║ ║ ║║ ║║║║ ╠╣ ╠╦╝║ ║║║║ ╠╩╗║╣ ╚╦╝
  473. // ╚ ╚═╝╝╚╝╚═╝ ╩ ╩╚═╝╝╚╝ ╚ ╩╚═╚═╝╩ ╩ ╩ ╩╚═╝ ╩
  474. //
  475. // Given a KEY value, find what join expression to use.
  476. var findJoinFunction = function findJoinFunction(key) {
  477. var fn;
  478. switch (key) {
  479. case 'JOIN':
  480. fn = 'join';
  481. break;
  482. case 'INNERJOIN':
  483. fn = 'innerJoin';
  484. break;
  485. case 'OUTERJOIN':
  486. fn = 'outerJoin';
  487. break;
  488. case 'CROSSJOIN':
  489. fn = 'crossJoin';
  490. break;
  491. case 'LEFTJOIN':
  492. fn = 'leftJoin';
  493. break;
  494. case 'LEFTOUTERJOIN':
  495. fn = 'leftOuterJoin';
  496. break;
  497. case 'RIGHTJOIN':
  498. fn = 'rightJoin';
  499. break;
  500. case 'RIGHTOUTERJOIN':
  501. fn = 'rightOuterJoin';
  502. break;
  503. case 'FULLOUTERJOIN':
  504. fn = 'fullOuterJoin';
  505. break;
  506. }
  507. return fn;
  508. };
  509. // ╔═╗╦═╗╔═╗╔═╗╔═╗╔═╗╔═╗ ╔═╗╦ ╔═╗╔╦╗ ╦╔═╗╦╔╗╔
  510. // ╠═╝╠╦╝║ ║║ ║╣ ╚═╗╚═╗ ╠╣ ║ ╠═╣ ║ ║║ ║║║║║
  511. // ╩ ╩╚═╚═╝╚═╝╚═╝╚═╝╚═╝ ╚ ╩═╝╩ ╩ ╩ ╚╝╚═╝╩╝╚╝
  512. //
  513. // Process a flat join. This is a join that doesn't need to be wrapped in
  514. // parenthesis.
  515. var processFlatJoin = function processFlatJoin(tokens, joinType, query) {
  516. // A JOIN token array assumes the following structure
  517. // { type: 'KEY', value: 'TABLE' },
  518. // { type: 'VALUE', value: 'contacts' },
  519. // { type: 'KEY', value: 'TABLE_KEY' },
  520. // { type: 'VALUE', value: 'users' },
  521. // { type: 'KEY', value: 'COLUMN_KEY' },
  522. // { type: 'VALUE', value: 'id' },
  523. // { type: 'KEY', value: 'TABLE_KEY' },
  524. // { type: 'VALUE', value: 'contacts' },
  525. // { type: 'KEY', value: 'COLUMN_KEY' },
  526. // { type: 'VALUE', value: 'user_id' }
  527. // Hold the values that make up the join expression
  528. var JOIN_TABLE = tokens[1] && tokens[1].value;
  529. var PARENT_TABLE = tokens[3] && tokens[3].value;
  530. var CHILD_TABLE = tokens[7] && tokens[7].value;
  531. var PARENT_COLUMN = tokens[5] && tokens[5].value;
  532. var CHILD_COLUMN = tokens[9] && tokens[9].value;
  533. // Hold the actual expression we will pass to Knex
  534. var joinExpr = [JOIN_TABLE, PARENT_TABLE + '.' + PARENT_COLUMN, '=', CHILD_TABLE + '.' + CHILD_COLUMN];
  535. // Find out which function to use
  536. var fn = findJoinFunction(joinType);
  537. buildQueryPiece(fn, joinExpr, query);
  538. };
  539. // ╔═╗╦═╗╔═╗╔═╗╔═╗╔═╗╔═╗ ╔═╗╦═╗╔═╗╦ ╦╔═╗╔═╗╔╦╗ ╦╔═╗╦╔╗╔
  540. // ╠═╝╠╦╝║ ║║ ║╣ ╚═╗╚═╗ ║ ╦╠╦╝║ ║║ ║╠═╝║╣ ║║ ║║ ║║║║║
  541. // ╩ ╩╚═╚═╝╚═╝╚═╝╚═╝╚═╝ ╚═╝╩╚═╚═╝╚═╝╩ ╚═╝═╩╝ ╚╝╚═╝╩╝╚╝
  542. //
  543. // Process a grouped join. This is a join that should be wrapped in parenthesis.
  544. var processGroupedJoin = function processGroupedJoin(tokens, joinType, query) {
  545. var pieces = [];
  546. var JOIN_TABLE = tokens[1] && tokens[1].value;
  547. // Remove the table name from the token set
  548. tokens = _.slice(tokens, 2);
  549. // Recurse through the tokens building up the pieces of the grouped fn
  550. var buildJoinPieces = function buildJoinPieces(_tokens) {
  551. var piece = {};
  552. // Find the start and end of the expression. To find the end, check if
  553. // there is another combinator value in the set.
  554. var start = _.findIndex(_tokens, { type: 'COMBINATOR' });
  555. var end = _.findIndex(_.slice(_tokens, start + 1), { type: 'COMBINATOR' });
  556. // Figure out what combinator was used
  557. var combinator = _tokens[start].value;
  558. piece.combinator = combinator;
  559. // Build up the join expression
  560. var PARENT_TABLE = _tokens[2] && _tokens[2].value;
  561. var CHILD_TABLE = _tokens[6] && _tokens[6].value;
  562. var PARENT_COLUMN = _tokens[4] && _tokens[4].value;
  563. var CHILD_COLUMN = _tokens[8] && _tokens[8].value;
  564. // Hold the actual expression we will pass to Knex
  565. piece.expr = [PARENT_TABLE + '.' + PARENT_COLUMN, '=', CHILD_TABLE + '.' + CHILD_COLUMN];
  566. // Add the piece to group of expressions
  567. pieces.push(piece);
  568. // If there are no more groups, return
  569. if (end < 0) {
  570. return;
  571. }
  572. // Set the _tokens to remove the process join piece and call again
  573. _tokens = _.slice(_tokens, end + 1);
  574. buildJoinPieces(_tokens);
  575. };
  576. // Kickoff the recursive parsing
  577. buildJoinPieces(tokens);
  578. // Now that all the pieces are built, build the function for passing into
  579. // Knex that will perform the actual grouping
  580. var groupFn = function groupFn() {
  581. var self = this;
  582. _.each(pieces, function applyFn(piece, idx) {
  583. var _fn = 'andOn';
  584. // The first item always uses the .on functions
  585. if (idx === 0) {
  586. _fn = 'on';
  587. } else if (piece.combinator === 'OR') {
  588. _fn = 'orOn';
  589. }
  590. self[_fn].apply(self, piece.expr);
  591. });
  592. };
  593. // Find out which function to use
  594. var joinFn = findJoinFunction(joinType);
  595. // Build the grouped join query
  596. buildQueryPiece(joinFn, [JOIN_TABLE, groupFn], query);
  597. };
  598. // ╔═╗╦═╗╔═╗╔═╗╔═╗╔═╗╔═╗ ╦╔═╗╦╔╗╔╔═╗
  599. // ╠═╝╠╦╝║ ║║ ║╣ ╚═╗╚═╗ ║║ ║║║║║╚═╗
  600. // ╩ ╩╚═╚═╝╚═╝╚═╝╚═╝╚═╝ ╚╝╚═╝╩╝╚╝╚═╝
  601. //
  602. // Takes an array of join tokens and builds various SQL joins.
  603. var processJoinGroup = function processJoinGroup(tokens, joinType, query) {
  604. // Check if there is a COMBINATOR token
  605. var hasCombinator = _.findIndex(tokens, { type: 'COMBINATOR' });
  606. // If not, process the flat join
  607. if (hasCombinator < 0) {
  608. processFlatJoin(tokens, joinType, query);
  609. return;
  610. }
  611. // Otherwise process the grouped join
  612. processGroupedJoin(tokens, joinType, query);
  613. };
  614. // ╔═╗╦═╗╔═╗╔═╗╔═╗╔═╗╔═╗ ╦ ╦╔╗╔╦╔═╗╔╗╔╔═╗
  615. // ╠═╝╠╦╝║ ║║ ║╣ ╚═╗╚═╗ ║ ║║║║║║ ║║║║╚═╗
  616. // ╩ ╩╚═╚═╝╚═╝╚═╝╚═╝╚═╝ ╚═╝╝╚╝╩╚═╝╝╚╝╚═╝
  617. //
  618. // Takes an array of subqueries and build a UNION or UNION ALL statement
  619. var processUnion = function processUnion(tokens, query, unionType) {
  620. _.each(tokens, function buildUnionSubquery(token) {
  621. // Build a standalone knex query builder
  622. var subQueryBuilder = knex.queryBuilder();
  623. // Pass the token to the parser
  624. tokenParser(subQueryBuilder, token);
  625. // Set the fn to run - either UNION or UNIONALL
  626. var fn = unionType === 'UNIONALL' ? 'unionAll' : 'union';
  627. // Add the subquery to the main query
  628. buildQueryPiece(fn, [subQueryBuilder, true], query);
  629. });
  630. };
  631. // ╔═╗╦═╗╔╦╗╔═╗╦═╗ ╔╗ ╦ ╦ ╔╗ ╦ ╦╦╦ ╔╦╗╔═╗╦═╗
  632. // ║ ║╠╦╝ ║║║╣ ╠╦╝ ╠╩╗╚╦╝ ╠╩╗║ ║║║ ║║║╣ ╠╦╝
  633. // ╚═╝╩╚══╩╝╚═╝╩╚═ ╚═╝ ╩ ╚═╝╚═╝╩╩═╝═╩╝╚═╝╩╚═
  634. //
  635. // Process ORDER BY expressions
  636. var orderByBuilder = function orderByBuilder(expr, expression) {
  637. var arr = [];
  638. // Handle KEY/VALUE pairs
  639. if (expr.type === 'KEY') {
  640. arr.push(expr.value);
  641. expression.push(arr);
  642. return expression;
  643. }
  644. // Set the VALUE pair
  645. if (expr.type === 'VALUE') {
  646. arr = _.last(expression);
  647. arr.push(expr.value);
  648. return expression;
  649. }
  650. };
  651. // ╦╔╗╔╔═╗╔═╗╦═╗╔╦╗ ╔╗ ╦ ╦╦╦ ╔╦╗╔═╗╦═╗
  652. // ║║║║╚═╗║╣ ╠╦╝ ║ ╠╩╗║ ║║║ ║║║╣ ╠╦╝
  653. // ╩╝╚╝╚═╝╚═╝╩╚═ ╩ ╚═╝╚═╝╩╩═╝═╩╝╚═╝╩╚═
  654. //
  655. // Builds an array of KEY/VALUE pairs to use as the insert clause.
  656. var insertBuilder = function insertBuilder(expr, expression) {
  657. var exprGroup = {};
  658. var keyName = undefined;
  659. // Handle bulk inserts
  660. if (_.isArray(expr)) {
  661. _.each(expr, function processBulkInsert(exprPiece) {
  662. // Handle KEY/VALUE pairs
  663. if (exprPiece.type === 'KEY') {
  664. exprGroup[exprPiece.value] = undefined;
  665. keyName = exprPiece.value;
  666. }
  667. // Set the VALUE pair
  668. if (exprPiece.type === 'VALUE') {
  669. exprGroup[keyName] = exprPiece.value;
  670. keyName = undefined;
  671. }
  672. });
  673. // Add the group to the expression
  674. expression.push(exprGroup);
  675. return expression;
  676. }
  677. // Handle KEY/VALUE pairs
  678. var arr = [];
  679. if (expr.type === 'KEY') {
  680. arr.push(expr.value);
  681. expression.push(arr);
  682. return expression;
  683. }
  684. // Set the VALUE pair
  685. if (expr.type === 'VALUE') {
  686. arr = _.last(expression);
  687. arr.push(expr.value);
  688. return expression;
  689. }
  690. };
  691. // ╦ ╦╔═╗╔╦╗╔═╗╔╦╗╔═╗ ╔╗ ╦ ╦╦╦ ╔╦╗╔═╗╦═╗
  692. // ║ ║╠═╝ ║║╠═╣ ║ ║╣ ╠╩╗║ ║║║ ║║║╣ ╠╦╝
  693. // ╚═╝╩ ═╩╝╩ ╩ ╩ ╚═╝ ╚═╝╚═╝╩╩═╝═╩╝╚═╝╩╚═
  694. //
  695. // Builds an array of KEY/VALUE pairs to use as the update clause
  696. var updateBuilder = function updateBuilder(expr, expression) {
  697. var arr = [];
  698. // Handle KEY/VALUE pairs
  699. if (expr.type === 'KEY') {
  700. arr.push(expr.value);
  701. expression.push(arr);
  702. return expression;
  703. }
  704. // Set the VALUE pair
  705. if (expr.type === 'VALUE') {
  706. arr = _.last(expression);
  707. arr.push(expr.value);
  708. return expression;
  709. }
  710. };
  711. // ╔═╗╦═╗╔═╗╔═╗╔═╗╔═╗╔═╗ ╦ ╦╔═╗╦ ╦ ╦╔═╗
  712. // ╠═╝╠╦╝║ ║║ ║╣ ╚═╗╚═╗ ╚╗╔╝╠═╣║ ║ ║║╣
  713. // ╩ ╩╚═╚═╝╚═╝╚═╝╚═╝╚═╝ ╚╝ ╩ ╩╩═╝╚═╝╚═╝
  714. //
  715. // Negotiates building a query piece based on the identifier
  716. var processValue = function processValue(expr, idx, options) {
  717. // Examine the identifier value
  718. switch (options.identifier) {
  719. case 'SELECT':
  720. buildQueryPiece('select', expr.value, options.query);
  721. break;
  722. case 'FROM':
  723. buildQueryPiece('from', expr.value, options.query);
  724. break;
  725. case 'SCHEMA':
  726. buildQueryPiece('withSchema', expr.value, options.query);
  727. break;
  728. case 'DISTINCT':
  729. buildQueryPiece('distinct', expr.value, options.query);
  730. break;
  731. case 'SUM':
  732. case 'AVG':
  733. if (!_.isArray(expr.value)) {
  734. expr.value = [expr.value];
  735. }
  736. _.each(expr.value, function processAvg(val) {
  737. buildQueryPiece(options.identifier.toLowerCase(), val, options.query);
  738. });
  739. break;
  740. case 'COUNT':
  741. buildQueryPiece('count', '*', options.query);
  742. break;
  743. case 'GROUPBY':
  744. buildQueryPiece('groupBy', expr.value, options.query);
  745. break;
  746. case 'INTO':
  747. buildQueryPiece('into', expr.value, options.query);
  748. break;
  749. case 'USING':
  750. buildQueryPiece('table', expr.value, options.query);
  751. break;
  752. case 'LIMIT':
  753. buildQueryPiece('limit', expr.value, options.query);
  754. break;
  755. case 'SKIP':
  756. buildQueryPiece('offset', expr.value, options.query);
  757. break;
  758. case 'RETURNING':
  759. // If the value is an array, wrap it in an additional array so the
  760. // .apply() call works correctly.
  761. if (_.isArray(expr.value)) {
  762. expr.value = [expr.value];
  763. }
  764. buildQueryPiece('returning', expr.value, options.query);
  765. break;
  766. case 'ORDERBY':
  767. // Look ahead and see if the next expression is an Identifier.
  768. // If so or if there is no next identifier, add the insert statments.
  769. options.nextExpr = undefined;
  770. options.nextExpr = options.tokenGroup[idx + 1];
  771. if (!options.nextExpr || options.nextExpr.type === 'IDENTIFIER') {
  772. _.each(options.expression, function processOrderBy(ordering) {
  773. buildQueryPiece('orderBy', ordering, options.query);
  774. });
  775. }
  776. break;
  777. case 'INSERT':
  778. // Look ahead and see if the next expression is an Identifier.
  779. // If so or if there is no next identifier, add the insert statments.
  780. options.nextExpr = undefined;
  781. options.nextExpr = options.tokenGroup[idx + 1];
  782. if (!options.nextExpr || options.nextExpr.type === 'IDENTIFIER') {
  783. var insertKeys = _.first(options.expression);
  784. // If the expression is an array of values, flatten the expression.
  785. // This represents a single record being inserted.
  786. if (_.isString(_.first(insertKeys))) {
  787. options.expression = fromPairs(options.expression);
  788. buildQueryPiece('insert', options.expression, options.query);
  789. // Otherwise use the bulk insert interface
  790. } else {
  791. buildQueryPiece('insert', [options.expression], options.query);
  792. }
  793. }
  794. break;
  795. case 'UPDATE':
  796. // Look ahead and see if the next expression is an Identifier.
  797. // If so or if there is no next identifier, add the update statments.
  798. options.nextExpr = undefined;
  799. options.nextExpr = options.tokenGroup[idx + 1];
  800. if (!options.nextExpr || options.nextExpr.type === 'IDENTIFIER') {
  801. // Flatten the expression
  802. options.expression = fromPairs(options.expression);
  803. buildQueryPiece('update', options.expression, options.query);
  804. }
  805. break;
  806. case 'WHERE':
  807. // Check the modifier to see if a different function other than
  808. // WHERE should be used. The most common is NOT.
  809. if (options.modifier && options.modifier.length) {
  810. if (options.modifier.length === 1 && _.first(options.modifier) === 'NOT') {
  811. if (expr.value === null) {
  812. options.fn = 'whereNotNull';
  813. }
  814. else {
  815. options.fn = 'whereNot';
  816. }
  817. }
  818. if (options.modifier.length === 1 && _.first(options.modifier) === 'IN') {
  819. options.fn = 'whereIn';
  820. }
  821. if (options.modifier.length === 1 && _.first(options.modifier) === 'NOTIN') {
  822. options.fn = 'whereNotIn';
  823. }
  824. // Otherwise use the where fn
  825. } else {
  826. options.fn = 'where';
  827. }
  828. // Set the second or third item in the array to the value
  829. buildQueryPiece(options.fn, options.expression, options.query);
  830. // Clear the modifier
  831. options.modifier = [];
  832. break;
  833. }
  834. };
  835. // ╔═╗═╗ ╦╔═╗╦═╗╔═╗╔═╗╔═╗╦╔═╗╔╗╔ ╔═╗╔═╗╦═╗╔═╗╔═╗╦═╗
  836. // ║╣ ╔╩╦╝╠═╝╠╦╝║╣ ╚═╗╚═╗║║ ║║║║ ╠═╝╠═╣╠╦╝╚═╗║╣ ╠╦╝
  837. // ╚═╝╩ ╚═╩ ╩╚═╚═╝╚═╝╚═╝╩╚═╝╝╚╝ ╩ ╩ ╩╩╚═╚═╝╚═╝╩╚═
  838. //
  839. // Parses each individual token piece.
  840. var expressionParser = function expressionParser(expr, idx, options) {
  841. // Handle identifiers by storing them on the fn
  842. if (expr.type === 'IDENTIFIER') {
  843. options.identifier = expr.value;
  844. // If the identifier is the DELETE key, we can go ahead and process it
  845. if (options.identifier === 'DELETE') {
  846. options.query.del();
  847. }
  848. return;
  849. }
  850. // NOT Modifier
  851. if (expr.type === 'CONDITION' && expr.value === 'NOT') {
  852. options.modifier = options.modifier || [];
  853. options.modifier.push(expr.value);
  854. return;
  855. }
  856. // IN Modifier
  857. if (expr.type === 'CONDITION' && expr.value === 'IN') {
  858. options.modifier = options.modifier || [];
  859. options.modifier.push(expr.value);
  860. return;
  861. }
  862. // NOTIN Modifier
  863. if (expr.type === 'CONDITION' && expr.value === 'NOTIN') {
  864. options.modifier = options.modifier || [];
  865. options.modifier.push(expr.value);
  866. return;
  867. }
  868. // AND Modifier
  869. if (expr.type === 'CONDITION' && expr.value === 'AND') {
  870. options.modifier = options.modifier || [];
  871. options.modifier.push(expr.value);
  872. return;
  873. }
  874. // Handle sets of values being inserted
  875. if (options.identifier === 'INSERT' && (expr.type === 'KEY' || expr.type === 'VALUE')) {
  876. options.expression = insertBuilder(expr, options.expression);
  877. }
  878. // Handle arrays of values being inserted
  879. if (options.identifier === 'INSERT' && _.isArray(expr)) {
  880. options.expression = insertBuilder(expr, options.expression);
  881. processValue(expr, idx, options);
  882. return;
  883. }
  884. // Handle sets of values being update
  885. if (options.identifier === 'UPDATE' && (expr.type === 'KEY' || expr.type === 'VALUE')) {
  886. options.expression = updateBuilder(expr, options.expression, options.query);
  887. }
  888. // Handle clauses in the WHERE value
  889. if (options.identifier === 'WHERE' && (expr.type === 'KEY' || expr.type === 'OPERATOR' || expr.type === 'VALUE')) {
  890. options.expression = whereBuilder(expr, options.expression, options.modifier, options.query);
  891. }
  892. // Handle ORDER BY statements
  893. if (options.identifier === 'ORDERBY' && (expr.type === 'KEY' || expr.type === 'VALUE')) {
  894. options.expression = orderByBuilder(expr, options.expression, options.query);
  895. }
  896. // Handle AS statements
  897. if (options.identifier === 'AS' && expr.type === 'VALUE') {
  898. options.query.as(expr.value);
  899. return;
  900. }
  901. // Handle UNION statements
  902. if (expr.type === 'UNION') {
  903. options.union = true;
  904. options.unionType = expr.value;
  905. return;
  906. }
  907. // Process value and use the appropriate Knex function
  908. if (expr.type === 'VALUE') {
  909. processValue(expr, idx, options);
  910. return;
  911. }
  912. // Handle SUBQUERY keys
  913. if (expr.type === 'SUBQUERY') {
  914. options.subQuery = true;
  915. return;
  916. }
  917. // ╔═╗╦═╗╔═╗╦ ╦╔═╗╦╔╗╔╔═╗
  918. // ║ ╦╠╦╝║ ║║ ║╠═╝║║║║║ ╦
  919. // ╚═╝╩╚═╚═╝╚═╝╩ ╩╝╚╝╚═╝
  920. //
  921. // If the expression is an array then the values should be grouped. Unless
  922. // they are describing join logic.
  923. if (_.isArray(expr)) {
  924. var joinTypes = [
  925. 'JOIN',
  926. 'INNERJOIN',
  927. 'OUTERJOIN',
  928. 'CROSSJOIN',
  929. 'LEFTJOIN',
  930. 'LEFTOUTERJOIN',
  931. 'RIGHTJOIN',
  932. 'RIGHTOUTERJOIN',
  933. 'FULLOUTERJOIN'
  934. ];
  935. // If the expression is an array of UNION subqueries, process each
  936. // one and toggle the UNION flag.
  937. if (options.union) {
  938. processUnion(expr, options.query, options.unionType);
  939. options.union = false;
  940. options.unionType = undefined;
  941. return;
  942. }
  943. // If the expression is a subQuery then process it standalone query
  944. // and pass it in as the expression value
  945. if (options.subQuery) {
  946. // Build a standalone knex query builder and pass it the expression
  947. var subQueryBuilder = knex.queryBuilder();
  948. tokenParser(subQueryBuilder, expr);
  949. // Toggle off the subquery flag
  950. options.subQuery = false;
  951. // Build the query using the subquery object as the value
  952. if (options.identifier === 'WHERE') {
  953. options.expression.push(subQueryBuilder);
  954. // If not a WHERE clause, just stick the subquery on the value
  955. } else {
  956. expr.value = subQueryBuilder;
  957. }
  958. // Process the value
  959. processValue(expr, idx, options);
  960. return;
  961. }
  962. var isJoin = _.indexOf(joinTypes, options.identifier);
  963. if (isJoin === -1) {
  964. processGroup(expr, false, options.expression, options.modifier, options.query);
  965. options.expression = [];
  966. return;
  967. }
  968. // Otherwise process the array of join logic
  969. processJoinGroup(expr, options.identifier, options.query);
  970. }
  971. };
  972. // ╔╦╗╦═╗╔═╗╔═╗ ╔═╗╔═╗╦═╗╔═╗╔═╗╦═╗
  973. // ║ ╠╦╝║╣ ║╣ ╠═╝╠═╣╠╦╝╚═╗║╣ ╠╦╝
  974. // ╩ ╩╚═╚═╝╚═╝ ╩ ╩ ╩╩╚═╚═╝╚═╝╩╚═
  975. //
  976. // Parses a group of tokens in the tree
  977. var treeParser = function treeParser(tokenGroup, query) {
  978. // Build up the default options
  979. var options = {
  980. identifier: undefined,
  981. modifier: [],
  982. fn: undefined,
  983. nextExpr: undefined,
  984. expression: [],
  985. query: query,
  986. tokenGroup: tokenGroup,
  987. subQuery: false,
  988. union: false
  989. };
  990. // Loop through each item in the group and build up the expression
  991. _.each(tokenGroup, function parseTokenGroup(expr, idx) {
  992. expressionParser(expr, idx, options);
  993. });
  994. };
  995. // ████████╗ ██████╗ ██╗ ██╗███████╗███╗ ██╗ ██████╗ █████╗ ██████╗ ███████╗███████╗██████╗
  996. // ╚══██╔══╝██╔═══██╗██║ ██╔╝██╔════╝████╗ ██║ ██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔════╝██╔══██╗
  997. // ██║ ██║ ██║█████╔╝ █████╗ ██╔██╗ ██║ ██████╔╝███████║██████╔╝███████╗█████╗ ██████╔╝
  998. // ██║ ██║ ██║██╔═██╗ ██╔══╝ ██║╚██╗██║ ██╔═══╝ ██╔══██║██╔══██╗╚════██║██╔══╝ ██╔══██╗
  999. // ██║ ╚██████╔╝██║ ██╗███████╗██║ ╚████║ ██║ ██║ ██║██║ ██║███████║███████╗██║ ██║
  1000. // ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝
  1001. //
  1002. // Loop through each token group in the tree and add to the query
  1003. var tokenParser = function tokenParser(query, tree) {
  1004. _.forEach(tree, function parseTree(tokenGroup) {
  1005. treeParser(tokenGroup, query);
  1006. });
  1007. };
  1008. // Run the token parser
  1009. var knexQuery = (function parseTree() {
  1010. var query = knex.queryBuilder();
  1011. tokenParser(query, tree);
  1012. return query;
  1013. })();
  1014. // Build up the actual SQL string
  1015. var _SQL = knexQuery.toSQL();
  1016. var text = _SQL.sql;
  1017. // Check if the bindings need to be positioned (aka changed to $1, $2 from ?, ?)
  1018. if (knexQuery.client && knexQuery.client.positionBindings) {
  1019. text = knexQuery.client.positionBindings(_SQL.sql);
  1020. }
  1021. return {
  1022. sql: text,
  1023. bindings: _SQL.bindings
  1024. };
  1025. };