blocks.test.coffee 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457
  1. ###
  2. Copyright (c) 2014 Ramesh Nair (hiddentao.com)
  3. Permission is hereby granted, free of charge, to any person
  4. obtaining a copy of this software and associated documentation
  5. files (the "Software"), to deal in the Software without
  6. restriction, including without limitation the rights to use,
  7. copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the
  9. Software is furnished to do so, subject to the following
  10. conditions:
  11. The above copyright notice and this permission notice shall be
  12. included in all copies or substantial portions of the Software.
  13. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  14. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  15. OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  16. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  17. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  18. WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. OTHER DEALINGS IN THE SOFTWARE.
  21. ###
  22. squel = require "../dist/squel-basic"
  23. {_, testCreator, assert, expect, should} = require './testbase'
  24. test = testCreator()
  25. test['Blocks'] =
  26. 'Block base class':
  27. beforeEach: ->
  28. @inst = new squel.cls.Block()
  29. 'instanceof of BaseBuilder': ->
  30. assert.instanceOf @inst, squel.cls.BaseBuilder
  31. 'options': ->
  32. expectedOptions = _.extend {}, squel.cls.DefaultQueryBuilderOptions,
  33. usingValuePlaceholders: true
  34. dummy: true
  35. @inst = new squel.cls.Block
  36. usingValuePlaceholders: true
  37. dummy: true
  38. assert.same expectedOptions, @inst.options
  39. '_toParamString()': ->
  40. assert.throws (=> @inst.toString()), 'Not yet implemented'
  41. 'exposedMethods()':
  42. 'returns methods': ->
  43. @inst['method1'] = -> return false
  44. @inst['method2'] = -> return false
  45. assert.ok ['method1', 'method2'], (name for name of @inst.exposedMethods())
  46. 'ignores methods prefixed with _': ->
  47. @inst['_method'] = -> return false
  48. assert.ok undefined is _.find (name for name of @inst.exposedMethods()), (name) ->
  49. return name is '_method'
  50. 'ignores toString()': ->
  51. assert.ok undefined is _.find (name for name of @inst.exposedMethods()), (name) ->
  52. return name is 'toString'
  53. 'cloning copies the options over': ->
  54. @inst.options.dummy = true;
  55. newinst = @inst.clone()
  56. @inst.options.dummy = false;
  57. assert.same true, newinst.options.dummy
  58. 'StringBlock':
  59. beforeEach: ->
  60. @cls = squel.cls.StringBlock
  61. @inst = new @cls
  62. 'instanceof of Block': ->
  63. assert.instanceOf @inst, squel.cls.Block
  64. '_toParamString()':
  65. 'non-parameterized': ->
  66. @inst = new @cls {}, 'TAG'
  67. assert.same @inst._toParamString(), {
  68. text: 'TAG'
  69. values: []
  70. }
  71. 'parameterized': ->
  72. @inst = new @cls {}, 'TAG'
  73. assert.same @inst._toParamString(buildParameterized: true), {
  74. text: 'TAG'
  75. values: []
  76. }
  77. 'FunctionBlock':
  78. beforeEach: ->
  79. @cls = squel.cls.FunctionBlock
  80. @inst = new @cls
  81. 'instanceof of Block': ->
  82. assert.instanceOf @inst, squel.cls.Block
  83. 'initial member values': ->
  84. assert.same [], @inst._values
  85. assert.same [], @inst._strings
  86. '_toParamString()':
  87. 'when not set': ->
  88. assert.same @inst._toParamString(), {
  89. text: ''
  90. values: []
  91. }
  92. 'non-parameterized': ->
  93. @inst.function('bla')
  94. @inst.function('bla2')
  95. assert.same @inst._toParamString(), {
  96. text: 'bla bla2',
  97. values: []
  98. }
  99. 'parameterized': ->
  100. @inst.function('bla ?', 2)
  101. @inst.function('bla2 ?', 3)
  102. assert.same @inst._toParamString(buildParameterized: true), {
  103. text: 'bla ? bla2 ?',
  104. values: [2, 3]
  105. }
  106. 'AbstractTableBlock':
  107. beforeEach: ->
  108. @cls = squel.cls.AbstractTableBlock
  109. @inst = new @cls()
  110. 'instanceof of Block': ->
  111. assert.instanceOf @inst, squel.cls.Block
  112. 'initial field values': ->
  113. assert.same [], @inst._tables
  114. 'has table':
  115. 'no': ->
  116. assert.same false, @inst._hasTable()
  117. 'yes': ->
  118. @inst._table('blah')
  119. assert.same true, @inst._hasTable()
  120. '_table()':
  121. 'saves inputs': ->
  122. @inst._table('table1')
  123. @inst._table('table2', 'alias2')
  124. @inst._table('table3')
  125. expectedFroms = [
  126. {
  127. table: 'table1',
  128. alias: null
  129. },
  130. {
  131. table: 'table2',
  132. alias: 'alias2'
  133. },
  134. {
  135. table: 'table3',
  136. alias: null
  137. }
  138. ]
  139. assert.same expectedFroms, @inst._tables
  140. 'sanitizes inputs': ->
  141. sanitizeTableSpy = test.mocker.stub @cls.prototype, '_sanitizeTable', -> return '_t'
  142. sanitizeAliasSpy = test.mocker.stub @cls.prototype, '_sanitizeTableAlias', -> return '_a'
  143. @inst._table('table', 'alias')
  144. assert.ok sanitizeTableSpy.calledWith 'table'
  145. assert.ok sanitizeAliasSpy.calledWithExactly 'alias'
  146. assert.same [ { table: '_t', alias: '_a' }], @inst._tables
  147. 'handles single-table mode': ->
  148. @inst.options.singleTable = true
  149. @inst._table('table1')
  150. @inst._table('table2')
  151. @inst._table('table3')
  152. expected = [
  153. {
  154. table: 'table3',
  155. alias: null
  156. }
  157. ]
  158. assert.same expected, @inst._tables
  159. 'builder as table': ->
  160. sanitizeTableSpy = test.mocker.spy @cls.prototype, '_sanitizeTable'
  161. innerTable1 = squel.select()
  162. innerTable2 = squel.select()
  163. @inst._table(innerTable1)
  164. @inst._table(innerTable2, 'Inner2')
  165. assert.ok sanitizeTableSpy.calledWithExactly innerTable1
  166. assert.ok sanitizeTableSpy.calledWithExactly innerTable2
  167. expected = [
  168. {
  169. alias: null
  170. table: innerTable1
  171. }
  172. {
  173. alias: 'Inner2'
  174. table: innerTable2
  175. }
  176. ]
  177. assert.same expected, @inst._tables
  178. '_toParamString()':
  179. beforeEach: ->
  180. @innerTable1 = squel.select().from('inner1').where('a = ?', 3)
  181. 'no table': ->
  182. assert.same @inst._toParamString(), {
  183. text: ''
  184. values: []
  185. }
  186. 'prefix': ->
  187. @inst.options.prefix = 'TEST'
  188. @inst._table('table2', 'alias2')
  189. assert.same @inst._toParamString(), {
  190. text: 'TEST table2 `alias2`',
  191. values: []
  192. }
  193. 'non-parameterized': ->
  194. @inst._table(@innerTable1)
  195. @inst._table('table2', 'alias2')
  196. @inst._table('table3')
  197. assert.same @inst._toParamString(), {
  198. text: '(SELECT * FROM inner1 WHERE (a = 3)), table2 `alias2`, table3'
  199. values: []
  200. }
  201. 'parameterized': ->
  202. @inst._table(@innerTable1)
  203. @inst._table('table2', 'alias2')
  204. @inst._table('table3')
  205. assert.same @inst._toParamString(buildParameterized: true), {
  206. text: '(SELECT * FROM inner1 WHERE (a = ?)), table2 `alias2`, table3'
  207. values: [3]
  208. }
  209. 'FromTableBlock':
  210. beforeEach: ->
  211. @cls = squel.cls.FromTableBlock
  212. @inst = new @cls()
  213. 'check prefix': ->
  214. assert.same @inst.options.prefix, 'FROM'
  215. 'instanceof of AbstractTableBlock': ->
  216. assert.instanceOf @inst, squel.cls.AbstractTableBlock
  217. 'from()':
  218. 'calls base class handler': ->
  219. baseMethodSpy = test.mocker.stub squel.cls.AbstractTableBlock.prototype, '_table'
  220. @inst.from('table1')
  221. @inst.from('table2', 'alias2')
  222. assert.same 2, baseMethodSpy.callCount
  223. assert.ok baseMethodSpy.calledWithExactly('table1', null)
  224. assert.ok baseMethodSpy.calledWithExactly('table2', 'alias2')
  225. 'UpdateTableBlock':
  226. beforeEach: ->
  227. @cls = squel.cls.UpdateTableBlock
  228. @inst = new @cls()
  229. 'instanceof of AbstractTableBlock': ->
  230. assert.instanceOf @inst, squel.cls.AbstractTableBlock
  231. 'check prefix': ->
  232. assert.same @inst.options.prefix, undefined
  233. 'table()':
  234. 'calls base class handler': ->
  235. baseMethodSpy = test.mocker.stub squel.cls.AbstractTableBlock.prototype, '_table'
  236. @inst.table('table1')
  237. @inst.table('table2', 'alias2')
  238. assert.same 2, baseMethodSpy.callCount
  239. assert.ok baseMethodSpy.calledWithExactly('table1', null)
  240. assert.ok baseMethodSpy.calledWithExactly('table2', 'alias2')
  241. 'TargetTableBlock':
  242. beforeEach: ->
  243. @cls = squel.cls.TargetTableBlock
  244. @inst = new @cls()
  245. 'instanceof of AbstractTableBlock': ->
  246. assert.instanceOf @inst, squel.cls.AbstractTableBlock
  247. 'check prefix': ->
  248. assert.same @inst.options.prefix, undefined
  249. 'table()':
  250. 'calls base class handler': ->
  251. baseMethodSpy = test.mocker.stub squel.cls.AbstractTableBlock.prototype, '_table'
  252. @inst.target('table1')
  253. @inst.target('table2')
  254. assert.same 2, baseMethodSpy.callCount
  255. assert.ok baseMethodSpy.calledWithExactly('table1')
  256. assert.ok baseMethodSpy.calledWithExactly('table2')
  257. 'IntoTableBlock':
  258. beforeEach: ->
  259. @cls = squel.cls.IntoTableBlock
  260. @inst = new @cls()
  261. 'instanceof of AbstractTableBlock': ->
  262. assert.instanceOf @inst, squel.cls.AbstractTableBlock
  263. 'check prefix': ->
  264. assert.same @inst.options.prefix, 'INTO'
  265. 'single table': ->
  266. assert.ok @inst.options.singleTable
  267. 'into()':
  268. 'calls base class handler': ->
  269. baseMethodSpy = test.mocker.stub squel.cls.AbstractTableBlock.prototype, '_table'
  270. @inst.into('table1')
  271. @inst.into('table2')
  272. assert.same 2, baseMethodSpy.callCount
  273. assert.ok baseMethodSpy.calledWith('table1')
  274. assert.ok baseMethodSpy.calledWith('table2')
  275. '_toParamString()':
  276. 'requires table to have been provided': ->
  277. try
  278. @inst._toParamString()
  279. throw new Error 'should not reach here'
  280. catch err
  281. assert.same 'Error: into() needs to be called', err.toString()
  282. 'GetFieldBlock':
  283. beforeEach: ->
  284. @cls = squel.cls.GetFieldBlock
  285. @inst = new @cls()
  286. 'instanceof of Block': ->
  287. assert.instanceOf @inst, squel.cls.Block
  288. 'fields() - object':
  289. 'saves inputs': ->
  290. fieldSpy = test.mocker.spy(@inst, 'field')
  291. @inst.fields({
  292. 'field1': null
  293. 'field2': 'alias2'
  294. 'field3': null
  295. }, { dummy: true})
  296. expected = [
  297. {
  298. name: 'field1',
  299. alias: null,
  300. options: {
  301. dummy: true
  302. }
  303. },
  304. {
  305. name: 'field2',
  306. alias: 'alias2'
  307. options: {
  308. dummy: true
  309. }
  310. },
  311. {
  312. name: 'field3',
  313. alias: null
  314. options: {
  315. dummy: true
  316. }
  317. }
  318. ]
  319. assert.ok fieldSpy.calledThrice
  320. assert.ok fieldSpy.calledWithExactly('field1', null, dummy: true)
  321. assert.ok fieldSpy.calledWithExactly('field2', 'alias2', dummy: true)
  322. assert.ok fieldSpy.calledWithExactly('field3', null, dummy: true)
  323. assert.same expected, @inst._fields
  324. 'fields() - array':
  325. 'saves inputs': ->
  326. fieldSpy = test.mocker.spy(@inst, 'field')
  327. @inst.fields([ 'field1', 'field2', 'field3' ], { dummy: true})
  328. expected = [
  329. {
  330. name: 'field1',
  331. alias: null
  332. options: {
  333. dummy: true
  334. }
  335. },
  336. {
  337. name: 'field2',
  338. alias: null
  339. options: {
  340. dummy: true
  341. }
  342. },
  343. {
  344. name: 'field3',
  345. alias: null
  346. options: {
  347. dummy: true
  348. }
  349. }
  350. ]
  351. assert.ok fieldSpy.calledThrice
  352. assert.ok fieldSpy.calledWithExactly('field1', null, dummy: true)
  353. assert.ok fieldSpy.calledWithExactly('field2', null, dummy: true)
  354. assert.ok fieldSpy.calledWithExactly('field3', null, dummy: true)
  355. assert.same expected, @inst._fields
  356. 'field()':
  357. 'saves inputs': ->
  358. @inst.field('field1')
  359. @inst.field('field2', 'alias2')
  360. @inst.field('field3')
  361. expected = [
  362. {
  363. name: 'field1',
  364. alias: null,
  365. options: {},
  366. },
  367. {
  368. name: 'field2',
  369. alias: 'alias2'
  370. options: {},
  371. },
  372. {
  373. name: 'field3',
  374. alias: null
  375. options: {},
  376. }
  377. ]
  378. assert.same expected, @inst._fields
  379. 'field() - discard duplicates':
  380. 'saves inputs': ->
  381. @inst.field('field1')
  382. @inst.field('field2', 'alias2')
  383. @inst.field('field2', 'alias2')
  384. @inst.field('field1', 'alias1')
  385. expected = [
  386. {
  387. name: 'field1',
  388. alias: null
  389. options: {},
  390. },
  391. {
  392. name: 'field2',
  393. alias: 'alias2'
  394. options: {},
  395. },
  396. {
  397. name: 'field1',
  398. alias: 'alias1'
  399. options: {},
  400. }
  401. ]
  402. assert.same expected, @inst._fields
  403. 'sanitizes inputs': ->
  404. sanitizeFieldSpy = test.mocker.stub @cls.prototype, '_sanitizeField', -> return '_f'
  405. sanitizeAliasSpy = test.mocker.stub @cls.prototype, '_sanitizeFieldAlias', -> return '_a'
  406. @inst.field('field1', 'alias1', { dummy: true})
  407. assert.ok sanitizeFieldSpy.calledWithExactly 'field1'
  408. assert.ok sanitizeAliasSpy.calledWithExactly 'alias1'
  409. assert.same @inst._fields, [ {
  410. name: '_f',
  411. alias: '_a'
  412. options:
  413. dummy: true
  414. } ]
  415. '_toParamString()':
  416. beforeEach: ->
  417. @queryBuilder = squel.select()
  418. @fromTableBlock = @queryBuilder.getBlock(squel.cls.FromTableBlock)
  419. 'returns all fields when none provided and table is set': ->
  420. @fromTableBlock._hasTable = -> true
  421. assert.same @inst._toParamString(queryBuilder: @queryBuilder), {
  422. text: '*',
  423. values: []
  424. }
  425. 'but returns nothing if no table set': ->
  426. @fromTableBlock._hasTable = -> false
  427. assert.same @inst._toParamString(queryBuilder: @queryBuilder), {
  428. text: ''
  429. values: []
  430. }
  431. 'returns formatted query phrase': ->
  432. beforeEach: ->
  433. @fromTableBlock._hasTable = -> true
  434. @inst.field(squel.str('GETDATE(?)', 3), 'alias1')
  435. @inst.field('field2', 'alias2', { dummy: true })
  436. @inst.field('field3')
  437. 'non-parameterized': ->
  438. assert.same @inst._toParamString(queryBuilder: @queryBuilder), {
  439. text: '(GETDATE(3)) AS "alias1", field2 AS "alias2", field3'
  440. values: []
  441. }
  442. 'parameterized': ->
  443. assert.same @inst._toParamString(queryBuilder: @queryBuilder, buildParameterized: true), {
  444. text: '(GETDATE(?)) AS "alias1", field2 AS "alias2", field3'
  445. values: [3]
  446. }
  447. 'AbstractSetFieldBlock':
  448. beforeEach: ->
  449. @cls = squel.cls.AbstractSetFieldBlock
  450. @inst = new @cls()
  451. 'instanceof of Block': ->
  452. assert.instanceOf @inst, squel.cls.Block
  453. '_set()':
  454. 'saves inputs': ->
  455. @inst._set('field1', 'value1', dummy: 1)
  456. @inst._set('field2', 'value2', dummy: 2)
  457. @inst._set('field3', 'value3', dummy: 3)
  458. @inst._set('field4')
  459. expectedFields = [ 'field1', 'field2', 'field3', 'field4' ]
  460. expectedValues = [ [ 'value1', 'value2', 'value3', undefined ] ]
  461. expectedFieldOptions = [ [ {dummy: 1}, {dummy: 2}, {dummy: 3}, {} ] ]
  462. assert.same expectedFields, @inst._fields
  463. assert.same expectedValues, @inst._values
  464. assert.same expectedFieldOptions, @inst._valueOptions
  465. 'sanitizes inputs': ->
  466. sanitizeFieldSpy = test.mocker.stub @cls.prototype, '_sanitizeField', -> '_f'
  467. sanitizeValueSpy = test.mocker.stub @cls.prototype, '_sanitizeValue', -> '_v'
  468. @inst._set('field1', 'value1', dummy: true)
  469. assert.ok sanitizeFieldSpy.calledWithExactly 'field1'
  470. assert.ok sanitizeValueSpy.calledWithExactly 'value1'
  471. assert.same [ '_f' ], @inst._fields
  472. assert.same [ [ '_v' ] ], @inst._values
  473. '_setFields()':
  474. 'saves inputs': ->
  475. @inst._setFields
  476. 'field1': 'value1'
  477. 'field2': 'value2'
  478. 'field3': 'value3'
  479. expectedFields = [ 'field1', 'field2', 'field3' ]
  480. expectedValues = [ [ 'value1', 'value2', 'value3'] ]
  481. expectedFieldOptions = [ [ {}, {}, {} ] ]
  482. assert.same expectedFields, @inst._fields
  483. assert.same expectedValues, @inst._values
  484. assert.same expectedFieldOptions, @inst._valueOptions
  485. 'sanitizes inputs': ->
  486. sanitizeFieldSpy = test.mocker.stub @cls.prototype, '_sanitizeField', -> '_f'
  487. sanitizeValueSpy = test.mocker.stub @cls.prototype, '_sanitizeValue', -> '_v'
  488. @inst._setFields({'field1': 'value1'}, {dummy: true})
  489. assert.ok sanitizeFieldSpy.calledWithExactly 'field1'
  490. assert.ok sanitizeValueSpy.calledWithExactly 'value1'
  491. assert.same [ '_f' ], @inst._fields
  492. assert.same [ [ '_v' ] ], @inst._values
  493. '_setFieldsRows()':
  494. 'saves inputs': ->
  495. @inst._setFieldsRows [
  496. {
  497. 'field1': 'value1'
  498. 'field2': 'value2'
  499. 'field3': 'value3'
  500. }
  501. {
  502. 'field1': 'value21'
  503. 'field2': 'value22'
  504. 'field3': 'value23'
  505. }
  506. ]
  507. expectedFields = [ 'field1', 'field2', 'field3' ]
  508. expectedValues = [ [ 'value1', 'value2', 'value3' ], [ 'value21', 'value22', 'value23' ] ]
  509. expectedFieldOptions = [ [ {}, {}, {} ], [ {}, {}, {} ] ]
  510. assert.same expectedFields, @inst._fields
  511. assert.same expectedValues, @inst._values
  512. assert.same expectedFieldOptions, @inst._valueOptions
  513. 'sanitizes inputs': ->
  514. sanitizeFieldSpy = test.mocker.stub @cls.prototype, '_sanitizeField', -> return '_f'
  515. sanitizeValueSpy = test.mocker.stub @cls.prototype, '_sanitizeValue', -> return '_v'
  516. @inst._setFieldsRows [
  517. {
  518. 'field1': 'value1'
  519. },
  520. {
  521. 'field1': 'value21'
  522. }
  523. ], { dummy: true }
  524. assert.ok sanitizeFieldSpy.calledWithExactly 'field1'
  525. assert.ok sanitizeValueSpy.calledWithExactly 'value1'
  526. assert.ok sanitizeValueSpy.calledWithExactly 'value21'
  527. assert.same [ '_f' ], @inst._fields
  528. assert.same [ [ '_v' ], [ '_v' ] ], @inst._values
  529. '_toParamString()': ->
  530. assert.throws ( => @inst._toParamString()), 'Not yet implemented'
  531. 'SetFieldBlock':
  532. beforeEach: ->
  533. @cls = squel.cls.SetFieldBlock
  534. @inst = new @cls()
  535. 'instanceof of AbstractSetFieldBlock': ->
  536. assert.instanceOf @inst, squel.cls.AbstractSetFieldBlock
  537. 'set()':
  538. 'calls to _set()': ->
  539. spy = test.mocker.stub @inst, '_set'
  540. @inst.set 'f', 'v', dummy: true
  541. assert.ok spy.calledWithExactly('f', 'v', dummy: true)
  542. 'setFields()':
  543. 'calls to _setFields()': ->
  544. spy = test.mocker.stub @inst, '_setFields'
  545. @inst.setFields 'f', dummy: true
  546. assert.ok spy.calledWithExactly('f', dummy: true)
  547. '_toParamString()':
  548. 'needs at least one field to have been provided': ->
  549. try
  550. @inst.toString()
  551. throw new Error 'should not reach here'
  552. catch err
  553. assert.same 'Error: set() needs to be called', err.toString()
  554. 'fields set':
  555. beforeEach: ->
  556. @inst.set('field0 = field0 + 1')
  557. @inst.set('field1', 'value1', { dummy: true })
  558. @inst.set('field2', 'value2')
  559. @inst.set('field3', squel.str('GETDATE(?)', 4))
  560. 'non-parameterized': ->
  561. assert.same @inst._toParamString(), {
  562. text: 'SET field0 = field0 + 1, field1 = \'value1\', field2 = \'value2\', field3 = (GETDATE(4))',
  563. values: [],
  564. }
  565. 'parameterized': ->
  566. assert.same @inst._toParamString(buildParameterized: true), {
  567. text: 'SET field0 = field0 + 1, field1 = ?, field2 = ?, field3 = (GETDATE(?))',
  568. values: ['value1', 'value2', 4],
  569. }
  570. 'InsertFieldValueBlock':
  571. beforeEach: ->
  572. @cls = squel.cls.InsertFieldValueBlock
  573. @inst = new @cls()
  574. 'instanceof of AbstractSetFieldBlock': ->
  575. assert.instanceOf @inst, squel.cls.AbstractSetFieldBlock
  576. 'set()':
  577. 'calls to _set()': ->
  578. spy = test.mocker.stub @inst, '_set'
  579. @inst.set 'f', 'v', dummy: true
  580. assert.ok spy.calledWithExactly('f', 'v', dummy: true)
  581. 'setFields()':
  582. 'calls to _setFields()': ->
  583. spy = test.mocker.stub @inst, '_setFields'
  584. @inst.setFields 'f', dummy: true
  585. assert.ok spy.calledWithExactly('f', dummy: true)
  586. 'setFieldsRows()':
  587. 'calls to _setFieldsRows()': ->
  588. spy = test.mocker.stub @inst, '_setFieldsRows'
  589. @inst.setFieldsRows 'f', dummy: true
  590. assert.ok spy.calledWithExactly('f', dummy: true)
  591. '_toParamString()':
  592. 'needs at least one field to have been provided': ->
  593. assert.same '', @inst.toString()
  594. 'got fields':
  595. beforeEach: ->
  596. @inst.setFieldsRows([
  597. { field1: 9, field2: 'value2', field3: squel.str('GETDATE(?)', 5) }
  598. { field1: 8, field2: true, field3: null }
  599. ])
  600. 'non-parameterized': ->
  601. assert.same @inst._toParamString(), {
  602. text: '(field1, field2, field3) VALUES (9, \'value2\', (GETDATE(5))), (8, TRUE, NULL)'
  603. values: [],
  604. }
  605. 'parameterized': ->
  606. assert.same @inst._toParamString(buildParameterized: true), {
  607. text: '(field1, field2, field3) VALUES (?, ?, (GETDATE(?))), (?, ?, ?)'
  608. values: [9, 'value2', 5, 8, true, null],
  609. }
  610. 'InsertFieldsFromQueryBlock':
  611. beforeEach: ->
  612. @cls = squel.cls.InsertFieldsFromQueryBlock
  613. @inst = new @cls()
  614. 'instanceof of Block': ->
  615. assert.instanceOf @inst, squel.cls.Block
  616. 'fromQuery()':
  617. 'sanitizes field names': ->
  618. spy = test.mocker.stub @inst, '_sanitizeField', -> 1
  619. qry = squel.select()
  620. @inst.fromQuery(['test', 'one', 'two'], qry)
  621. assert.ok spy.calledThrice
  622. assert.ok spy.calledWithExactly 'test'
  623. assert.ok spy.calledWithExactly 'one'
  624. assert.ok spy.calledWithExactly 'two'
  625. 'sanitizes query': ->
  626. spy = test.mocker.stub @inst, '_sanitizeBaseBuilder', -> 1
  627. qry = 123
  628. @inst.fromQuery(['test', 'one', 'two'], qry)
  629. assert.ok spy.calledOnce
  630. assert.ok spy.calledWithExactly qry
  631. 'overwrites existing values': ->
  632. @inst._fields = 1
  633. @inst._query = 2
  634. qry = squel.select()
  635. @inst.fromQuery(['test', 'one', 'two'], qry)
  636. assert.same qry, @inst._query
  637. assert.same ['test', 'one', 'two'], @inst._fields
  638. '_toParamString()':
  639. 'needs fromQuery() to have been called': ->
  640. assert.same @inst._toParamString(), {
  641. text: ''
  642. values: []
  643. }
  644. 'default':
  645. beforeEach: ->
  646. @qry = squel.select().from('mega').where('a = ?', 5)
  647. @inst.fromQuery ['test', 'one', 'two'], @qry
  648. 'non-parameterized': ->
  649. assert.same @inst._toParamString(), {
  650. text: "(test, one, two) (SELECT * FROM mega WHERE (a = 5))"
  651. values: []
  652. }
  653. 'parameterized': ->
  654. assert.same @inst._toParamString(buildParameterized: true), {
  655. text: "(test, one, two) (SELECT * FROM mega WHERE (a = ?))"
  656. values: [5]
  657. }
  658. 'DistinctBlock':
  659. beforeEach: ->
  660. @cls = squel.cls.DistinctBlock
  661. @inst = new @cls()
  662. 'instanceof of Block': ->
  663. assert.instanceOf @inst, squel.cls.Block
  664. '_toParamString()':
  665. 'output nothing if not set': ->
  666. assert.same @inst._toParamString(), {
  667. text: ''
  668. values: []
  669. }
  670. 'output DISTINCT if set': ->
  671. @inst.distinct()
  672. assert.same @inst._toParamString(), {
  673. text: 'DISTINCT'
  674. values: []
  675. }
  676. 'GroupByBlock':
  677. beforeEach: ->
  678. @cls = squel.cls.GroupByBlock
  679. @inst = new @cls()
  680. 'instanceof of Block': ->
  681. assert.instanceOf @inst, squel.cls.Block
  682. 'group()':
  683. 'adds to list': ->
  684. @inst.group('field1')
  685. @inst.group('field2')
  686. assert.same ['field1', 'field2'], @inst._groups
  687. 'sanitizes inputs': ->
  688. sanitizeFieldSpy = test.mocker.stub @cls.prototype, '_sanitizeField', -> return '_f'
  689. @inst.group('field1')
  690. assert.ok sanitizeFieldSpy.calledWithExactly 'field1'
  691. assert.same ['_f'], @inst._groups
  692. 'toString()':
  693. 'output nothing if no fields set': ->
  694. @inst._groups = []
  695. assert.same '', @inst.toString()
  696. 'output GROUP BY': ->
  697. @inst.group('field1')
  698. @inst.group('field2')
  699. assert.same 'GROUP BY field1, field2', @inst.toString()
  700. 'OffsetBlock':
  701. beforeEach: ->
  702. @cls = squel.cls.OffsetBlock
  703. @inst = new @cls()
  704. 'instanceof of Block': ->
  705. assert.instanceOf @inst, squel.cls.Block
  706. 'offset()':
  707. 'set value': ->
  708. @inst.offset(1)
  709. assert.same 1, @inst._offsets
  710. @inst.offset(22)
  711. assert.same 22, @inst._offsets
  712. 'sanitizes inputs': ->
  713. sanitizeSpy = test.mocker.stub @cls.prototype, '_sanitizeLimitOffset', -> return 234
  714. @inst.offset(23)
  715. assert.ok sanitizeSpy.calledWithExactly 23
  716. assert.same 234, @inst._offsets
  717. 'toString()':
  718. 'output nothing if not set': ->
  719. @inst._offsets = null
  720. assert.same '', @inst.toString()
  721. 'output OFFSET': ->
  722. @inst.offset(12)
  723. assert.same 'OFFSET 12', @inst.toString()
  724. 'AbstractConditionBlock':
  725. beforeEach: ->
  726. @cls = squel.cls.AbstractConditionBlock
  727. @inst = new @cls {
  728. verb: 'ACB'
  729. }
  730. class squel.cls.MockConditionBlock extends squel.cls.AbstractConditionBlock
  731. constructor: (options) ->
  732. super _.extend({}, options, {verb: 'MOCKVERB'})
  733. mockCondition: (condition, values...) ->
  734. @_condition condition, values...
  735. class squel.cls.MockSelectWithCondition extends squel.cls.Select
  736. constructor: (options, blocks = null) ->
  737. blocks = [
  738. new squel.cls.StringBlock(options, 'SELECT'),
  739. new squel.cls.GetFieldBlock(options),
  740. new squel.cls.FromTableBlock(options),
  741. new squel.cls.MockConditionBlock(options)
  742. ]
  743. super options, blocks
  744. 'instanceof of Block': ->
  745. assert.instanceOf @inst, squel.cls.Block
  746. '_condition()':
  747. 'adds to list': ->
  748. @inst._condition('a = 1')
  749. @inst._condition('b = 2 OR c = 3')
  750. assert.same [
  751. {
  752. expr: 'a = 1'
  753. values: []
  754. }
  755. {
  756. expr: 'b = 2 OR c = 3'
  757. values: []
  758. }
  759. ], @inst._conditions
  760. 'sanitizes inputs': ->
  761. sanitizeFieldSpy = test.mocker.stub @cls.prototype, '_sanitizeExpression', -> return '_c'
  762. @inst._condition('a = 1')
  763. assert.ok sanitizeFieldSpy.calledWithExactly 'a = 1'
  764. assert.same [{
  765. expr: '_c'
  766. values: []
  767. }], @inst._conditions
  768. '_toParamString()':
  769. 'output nothing if no conditions set': ->
  770. assert.same @inst._toParamString(), {
  771. text: ''
  772. values: []
  773. }
  774. 'output QueryBuilder ':
  775. beforeEach: ->
  776. subquery = new squel.cls.MockSelectWithCondition()
  777. subquery.field('col1').from('table1').mockCondition('field1 = ?', 10)
  778. @inst._condition('a in ?', subquery)
  779. @inst._condition('b = ? OR c = ?', 2, 3)
  780. @inst._condition('d in ?', [4, 5, 6])
  781. 'non-parameterized': ->
  782. assert.same @inst._toParamString(), {
  783. text: 'ACB (a in (SELECT col1 FROM table1 MOCKVERB (field1 = 10))) AND (b = 2 OR c = 3) AND (d in (4, 5, 6))'
  784. values: []
  785. }
  786. 'parameterized': ->
  787. assert.same @inst._toParamString(buildParameterized: true), {
  788. text: 'ACB (a in (SELECT col1 FROM table1 MOCKVERB (field1 = ?))) AND (b = ? OR c = ?) AND (d in (?, ?, ?))'
  789. values: [10, 2, 3, 4, 5, 6]
  790. }
  791. 'Fix for #64 - toString() does not change object':
  792. beforeEach: ->
  793. @inst._condition('a = ?', 1)
  794. @inst._condition('b = ? OR c = ?', 2, 3)
  795. @inst._condition('d in ?', [4, 5, 6])
  796. @inst._toParamString()
  797. @inst._toParamString()
  798. 'non-parameterized': ->
  799. assert.same @inst._toParamString(), {
  800. text: 'ACB (a = 1) AND (b = 2 OR c = 3) AND (d in (4, 5, 6))'
  801. values: []
  802. }
  803. 'parameterized': ->
  804. assert.same @inst._toParamString(buildParameterized: true), {
  805. text: 'ACB (a = ?) AND (b = ? OR c = ?) AND (d in (?, ?, ?))'
  806. values: [1, 2, 3, 4, 5, 6]
  807. }
  808. 'Fix for #226 - empty expressions':
  809. beforeEach: ->
  810. @inst._condition('a = ?', 1)
  811. @inst._condition(squel.expr())
  812. 'non-parameterized': ->
  813. assert.same @inst._toParamString(), {
  814. text: 'ACB (a = 1)'
  815. values: []
  816. }
  817. 'parameterized': ->
  818. assert.same @inst._toParamString(buildParameterized: true), {
  819. text: 'ACB (a = ?)'
  820. values: [1]
  821. }
  822. 'WhereBlock':
  823. beforeEach: ->
  824. @cls = squel.cls.WhereBlock
  825. @inst = new @cls()
  826. 'instanceof of AbstractConditionBlock': ->
  827. assert.instanceOf @inst, squel.cls.AbstractConditionBlock
  828. 'sets verb to WHERE': ->
  829. @inst = new @cls
  830. assert.same 'WHERE', @inst.options.verb
  831. '_toParamString()':
  832. 'output nothing if no conditions set': ->
  833. assert.same @inst._toParamString(), {
  834. text: ''
  835. values: []
  836. }
  837. 'output':
  838. beforeEach: ->
  839. subquery = new squel.cls.Select()
  840. subquery.field('col1').from('table1').where('field1 = ?', 10)
  841. @inst.where('a in ?', subquery)
  842. @inst.where('b = ? OR c = ?', 2, 3)
  843. @inst.where('d in ?', [4, 5, 6])
  844. 'non-parameterized': ->
  845. assert.same @inst._toParamString(), {
  846. text: 'WHERE (a in (SELECT col1 FROM table1 WHERE (field1 = 10))) AND (b = 2 OR c = 3) AND (d in (4, 5, 6))'
  847. values: []
  848. }
  849. 'parameterized': ->
  850. assert.same @inst._toParamString(buildParameterized: true), {
  851. text: 'WHERE (a in (SELECT col1 FROM table1 WHERE (field1 = ?))) AND (b = ? OR c = ?) AND (d in (?, ?, ?))'
  852. values: [10, 2, 3, 4, 5, 6]
  853. }
  854. 'HavingBlock':
  855. beforeEach: ->
  856. @cls = squel.cls.HavingBlock
  857. @inst = new @cls()
  858. 'instanceof of AbstractConditionBlock': ->
  859. assert.instanceOf @inst, squel.cls.AbstractConditionBlock
  860. 'sets verb': ->
  861. @inst = new @cls
  862. assert.same 'HAVING', @inst.options.verb
  863. '_toParamString()':
  864. 'output nothing if no conditions set': ->
  865. assert.same @inst._toParamString(), {
  866. text: ''
  867. values: []
  868. }
  869. 'output':
  870. beforeEach: ->
  871. subquery = new squel.cls.Select()
  872. subquery.field('col1').from('table1').where('field1 = ?', 10)
  873. @inst.having('a in ?', subquery)
  874. @inst.having('b = ? OR c = ?', 2, 3)
  875. @inst.having('d in ?', [4, 5, 6])
  876. 'non-parameterized': ->
  877. assert.same @inst._toParamString(), {
  878. text: 'HAVING (a in (SELECT col1 FROM table1 WHERE (field1 = 10))) AND (b = 2 OR c = 3) AND (d in (4, 5, 6))'
  879. values: []
  880. }
  881. 'parameterized': ->
  882. assert.same @inst._toParamString(buildParameterized: true), {
  883. text: 'HAVING (a in (SELECT col1 FROM table1 WHERE (field1 = ?))) AND (b = ? OR c = ?) AND (d in (?, ?, ?))'
  884. values: [10, 2, 3, 4, 5, 6]
  885. }
  886. 'OrderByBlock':
  887. beforeEach: ->
  888. @cls = squel.cls.OrderByBlock
  889. @inst = new @cls()
  890. 'instanceof of Block': ->
  891. assert.instanceOf @inst, squel.cls.Block
  892. 'order()':
  893. 'adds to list': ->
  894. @inst.order('field1')
  895. @inst.order('field2', false)
  896. @inst.order('field3', true)
  897. expected = [
  898. {
  899. field: 'field1',
  900. dir: true
  901. values: []
  902. },
  903. {
  904. field: 'field2',
  905. dir: false
  906. values: []
  907. },
  908. {
  909. field: 'field3',
  910. dir: true
  911. values: []
  912. }
  913. ]
  914. assert.same @inst._orders, expected
  915. 'sanitizes inputs': ->
  916. sanitizeFieldSpy = test.mocker.stub @cls.prototype, '_sanitizeField', -> return '_f'
  917. @inst.order('field1')
  918. assert.ok sanitizeFieldSpy.calledWithExactly 'field1'
  919. assert.same @inst._orders, [ { field: '_f', dir: true, values: [] } ]
  920. 'saves additional values': ->
  921. @inst.order('field1', false, 1.2, 4)
  922. assert.same @inst._orders, [ { field: 'field1', dir: false, values: [1.2, 4] } ]
  923. '_toParamString()':
  924. 'empty': ->
  925. assert.same @inst._toParamString(), {
  926. text: '', values: []
  927. }
  928. 'default': ->
  929. beforeEach: ->
  930. @inst.order('field1')
  931. @inst.order('field2', false)
  932. @inst.order('GET(?, ?)', true, 2.5 ,5)
  933. 'non-parameterized': ->
  934. assert.same @inst._toParamString(), {
  935. text: 'ORDER BY field1 ASC, field2 DESC, GET(2.5, 5) ASC',
  936. values: []
  937. }
  938. 'parameterized': ->
  939. assert.same @inst._toParamString(buildParameterized: true), {
  940. text: 'ORDER BY field1 ASC, field2 DESC, GET(?, ?) ASC',
  941. values: [2.5, 5]
  942. }
  943. 'LimitBlock':
  944. beforeEach: ->
  945. @cls = squel.cls.LimitBlock
  946. @inst = new @cls()
  947. 'instanceof of Block': ->
  948. assert.instanceOf @inst, squel.cls.Block
  949. 'limit()':
  950. 'set value': ->
  951. @inst.limit(1)
  952. assert.same 1, @inst._limit
  953. @inst.limit(22)
  954. assert.same 22, @inst._limit
  955. 'sanitizes inputs': ->
  956. sanitizeSpy = test.mocker.stub @cls.prototype, '_sanitizeLimitOffset', -> return 234
  957. @inst.limit(23)
  958. assert.ok sanitizeSpy.calledWithExactly 23
  959. assert.same 234, @inst._limit
  960. '_toParamString()':
  961. 'output nothing if not set': ->
  962. assert.same @inst._toParamString(), {
  963. text: '',
  964. values: []
  965. }
  966. 'default':
  967. beforeEach: ->
  968. @inst.limit(10)
  969. 'non-parameterized': ->
  970. assert.same @inst._toParamString(), {
  971. text: 'LIMIT 10'
  972. values: []
  973. }
  974. 'parameterized': ->
  975. assert.same @inst._toParamString(buildParameterized: true), {
  976. text: 'LIMIT 10'
  977. values: []
  978. }
  979. 'JoinBlock':
  980. beforeEach: ->
  981. @cls = squel.cls.JoinBlock
  982. @inst = new @cls()
  983. 'instanceof of Block': ->
  984. assert.instanceOf @inst, squel.cls.Block
  985. 'join()':
  986. 'adds to list': ->
  987. @inst.join('table1')
  988. @inst.join('table2', null, 'b = 1', 'LEFT')
  989. @inst.join('table3', 'alias3', 'c = 1', 'RIGHT')
  990. @inst.join('table4', 'alias4', 'd = 1', 'OUTER')
  991. @inst.join('table5', 'alias5', null, 'CROSS')
  992. expected = [
  993. {
  994. type: 'INNER',
  995. table: 'table1',
  996. alias: null,
  997. condition: null
  998. },
  999. {
  1000. type: 'LEFT',
  1001. table: 'table2',
  1002. alias: null,
  1003. condition: 'b = 1'
  1004. },
  1005. {
  1006. type: 'RIGHT',
  1007. table: 'table3',
  1008. alias: 'alias3',
  1009. condition: 'c = 1'
  1010. },
  1011. {
  1012. type: 'OUTER',
  1013. table: 'table4',
  1014. alias: 'alias4',
  1015. condition: 'd = 1'
  1016. },
  1017. {
  1018. type: 'CROSS',
  1019. table: 'table5',
  1020. alias: 'alias5',
  1021. condition: null
  1022. }
  1023. ]
  1024. assert.same @inst._joins, expected
  1025. 'sanitizes inputs': ->
  1026. sanitizeTableSpy = test.mocker.stub @cls.prototype, '_sanitizeTable', -> return '_t'
  1027. sanitizeAliasSpy = test.mocker.stub @cls.prototype, '_sanitizeTableAlias', -> return '_a'
  1028. sanitizeConditionSpy = test.mocker.stub @cls.prototype, '_sanitizeExpression', -> return '_c'
  1029. @inst.join('table1', 'alias1', 'a = 1')
  1030. assert.ok sanitizeTableSpy.calledWithExactly 'table1', true
  1031. assert.ok sanitizeAliasSpy.calledWithExactly 'alias1'
  1032. assert.ok sanitizeConditionSpy.calledWithExactly 'a = 1'
  1033. expected = [
  1034. {
  1035. type: 'INNER',
  1036. table: '_t',
  1037. alias: '_a',
  1038. condition: '_c'
  1039. }
  1040. ]
  1041. assert.same @inst._joins, expected
  1042. 'nested queries': ->
  1043. inner1 = squel.select()
  1044. inner2 = squel.select()
  1045. inner3 = squel.select()
  1046. inner4 = squel.select()
  1047. inner5 = squel.select()
  1048. inner6 = squel.select()
  1049. @inst.join(inner1)
  1050. @inst.join(inner2, null, 'b = 1', 'LEFT')
  1051. @inst.join(inner3, 'alias3', 'c = 1', 'RIGHT')
  1052. @inst.join(inner4, 'alias4', 'd = 1', 'OUTER')
  1053. @inst.join(inner5, 'alias5', 'e = 1', 'FULL')
  1054. @inst.join(inner6, 'alias6', null, 'CROSS')
  1055. expected = [
  1056. {
  1057. type: 'INNER',
  1058. table: inner1,
  1059. alias: null,
  1060. condition: null
  1061. },
  1062. {
  1063. type: 'LEFT',
  1064. table: inner2,
  1065. alias: null,
  1066. condition: 'b = 1'
  1067. },
  1068. {
  1069. type: 'RIGHT',
  1070. table: inner3,
  1071. alias: 'alias3',
  1072. condition: 'c = 1'
  1073. },
  1074. {
  1075. type: 'OUTER',
  1076. table: inner4,
  1077. alias: 'alias4',
  1078. condition: 'd = 1'
  1079. },
  1080. {
  1081. type: 'FULL',
  1082. table: inner5,
  1083. alias: 'alias5',
  1084. condition: 'e = 1'
  1085. },
  1086. {
  1087. type: 'CROSS',
  1088. table: inner6,
  1089. alias: 'alias6',
  1090. condition: null
  1091. }
  1092. ]
  1093. assert.same @inst._joins, expected
  1094. 'left_join()':
  1095. 'calls join()': ->
  1096. joinSpy = test.mocker.stub(@inst, 'join')
  1097. @inst.left_join('t', 'a', 'c')
  1098. assert.ok joinSpy.calledOnce
  1099. assert.ok joinSpy.calledWithExactly('t', 'a', 'c', 'LEFT')
  1100. '_toParamString()':
  1101. 'output nothing if nothing set': ->
  1102. assert.same @inst._toParamString(), {
  1103. text: '',
  1104. values: []
  1105. }
  1106. 'output JOINs with nested queries':
  1107. beforeEach: ->
  1108. inner2 = squel.select().function('GETDATE(?)', 2)
  1109. inner3 = squel.select().from('3')
  1110. inner4 = squel.select().from('4')
  1111. inner5 = squel.select().from('5')
  1112. expr = squel.expr().and('field1 = ?', 99)
  1113. @inst.join('table')
  1114. @inst.join(inner2, null, 'b = 1', 'LEFT')
  1115. @inst.join(inner3, 'alias3', 'c = 1', 'RIGHT')
  1116. @inst.join(inner4, 'alias4', 'e = 1', 'FULL')
  1117. @inst.join(inner5, 'alias5', expr, 'CROSS')
  1118. 'non-parameterized': ->
  1119. assert.same @inst._toParamString(), {
  1120. text: 'INNER JOIN table LEFT JOIN (SELECT GETDATE(2)) ON (b = 1) RIGHT JOIN (SELECT * FROM 3) `alias3` ON (c = 1) FULL JOIN (SELECT * FROM 4) `alias4` ON (e = 1) CROSS JOIN (SELECT * FROM 5) `alias5` ON (field1 = 99)'
  1121. values: []
  1122. }
  1123. 'parameterized': ->
  1124. assert.same @inst._toParamString(buildParameterized: true), {
  1125. text: 'INNER JOIN table LEFT JOIN (SELECT GETDATE(?)) ON (b = 1) RIGHT JOIN (SELECT * FROM 3) `alias3` ON (c = 1) FULL JOIN (SELECT * FROM 4) `alias4` ON (e = 1) CROSS JOIN (SELECT * FROM 5) `alias5` ON (field1 = ?)'
  1126. values: [2, 99]
  1127. }
  1128. module?.exports[require('path').basename(__filename)] = test