QueryTest.php 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957
  1. <?php
  2. /**
  3. * PHP Version 5.4
  4. *
  5. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  6. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  7. *
  8. * Licensed under The MIT License
  9. * For full copyright and license information, please see the LICENSE.txt
  10. * Redistributions of files must retain the above copyright notice.
  11. *
  12. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  13. * @link http://cakephp.org CakePHP(tm) Project
  14. * @since CakePHP(tm) v 3.0.0
  15. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  16. */
  17. namespace Cake\Test\TestCase\Database;
  18. use Cake\Core\Configure;
  19. use Cake\Database\ConnectionManager;
  20. use Cake\Database\Query;
  21. use Cake\TestSuite\TestCase;
  22. /**
  23. * Tests Query class
  24. *
  25. */
  26. class QueryTest extends TestCase {
  27. public $fixtures = ['core.article', 'core.author', 'core.comment'];
  28. const ARTICLE_COUNT = 3;
  29. const AUTHOR_COUNT = 4;
  30. const COMMENT_COUNT = 6;
  31. public function setUp() {
  32. parent::setUp();
  33. $this->connection = ConnectionManager::get('test');
  34. }
  35. public function tearDown() {
  36. parent::tearDown();
  37. unset($this->connection);
  38. }
  39. /**
  40. * Tests that it is possible to obtain expression results from a query
  41. *
  42. * @return void
  43. */
  44. public function testSelectFieldsOnly() {
  45. $query = new Query($this->connection);
  46. $result = $query->select('1 + 1')->execute();
  47. $this->assertInstanceOf('Cake\Database\StatementInterface', $result);
  48. $this->assertEquals([2], $result->fetch());
  49. //This new field should be appended
  50. $result = $query->select(array('1 + 3'))->execute();
  51. $this->assertInstanceOf('Cake\Database\StatementInterface', $result);
  52. $this->assertEquals([2, 4], $result->fetch());
  53. //This should now overwrite all previous fields
  54. $result = $query->select(array('1 + 2', '1 + 5'), true)->execute();
  55. $this->assertEquals([3, 6], $result->fetch());
  56. }
  57. /**
  58. * Tests that it is possible to pass a closure as fields in select()
  59. *
  60. * @return void
  61. */
  62. public function testSelectClosure() {
  63. $query = new Query($this->connection);
  64. $result = $query->select(function($q) use ($query) {
  65. $this->assertSame($query, $q);
  66. return ['1 + 2', '1 + 5'];
  67. })->execute();
  68. $this->assertEquals([3, 6], $result->fetch());
  69. }
  70. /**
  71. * Tests it is possible to select fields from tables with no conditions
  72. *
  73. * @return void
  74. */
  75. public function testSelectFieldsFromTable() {
  76. $query = new Query($this->connection);
  77. $result = $query->select(array('body', 'author_id'))->from('articles')->execute();
  78. $this->assertEquals(array('body' => 'First Article Body', 'author_id' => 1), $result->fetch('assoc'));
  79. $this->assertEquals(array('body' => 'Second Article Body', 'author_id' => 3), $result->fetch('assoc'));
  80. //Append more tables to next execution
  81. $result = $query->select('name')->from(array('authors'))->order(['name' => 'desc', 'articles.id' => 'asc'])->execute();
  82. $this->assertEquals(array('body' => 'First Article Body', 'author_id' => 1, 'name' => 'nate'), $result->fetch('assoc'));
  83. $this->assertEquals(array('body' => 'Second Article Body', 'author_id' => 3, 'name' => 'nate'), $result->fetch('assoc'));
  84. $this->assertEquals(array('body' => 'Third Article Body', 'author_id' => 1, 'name' => 'nate'), $result->fetch('assoc'));
  85. //Overwrite tables and only fetch from authors
  86. $result = $query->select('name', true)->from('authors', true)->order(['name' => 'desc'], true)->execute();
  87. $this->assertEquals(array('nate'), $result->fetch());
  88. $this->assertEquals(array('mariano'), $result->fetch());
  89. $this->assertCount(4, $result);
  90. }
  91. /**
  92. * Tests it is possible to select aliased fields
  93. *
  94. * @return void
  95. */
  96. public function testSelectAliasedFieldsFromTable() {
  97. $query = new Query($this->connection);
  98. $result = $query->select(['text' => 'body', 'author_id'])->from('articles')->execute();
  99. $this->assertEquals(array('text' => 'First Article Body', 'author_id' => 1), $result->fetch('assoc'));
  100. $this->assertEquals(array('text' => 'Second Article Body', 'author_id' => 3), $result->fetch('assoc'));
  101. $query = new Query($this->connection);
  102. $result = $query->select(['text' => 'body', 'author' => 'author_id'])->from('articles')->execute();
  103. $this->assertEquals(array('text' => 'First Article Body', 'author' => 1), $result->fetch('assoc'));
  104. $this->assertEquals(array('text' => 'Second Article Body', 'author' => 3), $result->fetch('assoc'));
  105. $query = new Query($this->connection);
  106. $query->select(['text' => 'body'])->select(['author_id', 'foo' => 'body']);
  107. $result = $query->from('articles')->execute();
  108. $this->assertEquals(array('foo' => 'First Article Body', 'text' => 'First Article Body', 'author_id' => 1), $result->fetch('assoc'));
  109. $this->assertEquals(array('foo' => 'Second Article Body', 'text' => 'Second Article Body', 'author_id' => 3), $result->fetch('assoc'));
  110. $query = new Query($this->connection);
  111. $exp = $query->newExpr()->add('1 + 1');
  112. $comp = $query->newExpr()->add(['author_id +' => 2]);
  113. $result = $query->select(['text' => 'body', 'two' => $exp, 'three' => $comp])
  114. ->from('articles')->execute();
  115. $this->assertEquals(array('text' => 'First Article Body', 'two' => 2, 'three' => 3), $result->fetch('assoc'));
  116. $this->assertEquals(array('text' => 'Second Article Body', 'two' => 2, 'three' => 5), $result->fetch('assoc'));
  117. }
  118. /**
  119. * Tests that tables can also be aliased and referenced in the select clause using such alias
  120. *
  121. * @return void
  122. */
  123. public function testSelectAliasedTables() {
  124. $query = new Query($this->connection);
  125. $result = $query->select(['text' => 'a.body', 'a.author_id'])
  126. ->from(['a' => 'articles'])->execute();
  127. $this->assertEquals(['text' => 'First Article Body', 'author_id' => 1], $result->fetch('assoc'));
  128. $this->assertEquals(['text' => 'Second Article Body', 'author_id' => 3], $result->fetch('assoc'));
  129. $result = $query->select(['name' => 'b.name'])->from(['b' => 'authors'])
  130. ->order(['text' => 'desc', 'name' => 'desc'])
  131. ->execute();
  132. $this->assertEquals(
  133. ['text' => 'Third Article Body', 'author_id' => 1, 'name' => 'nate'],
  134. $result->fetch('assoc')
  135. );
  136. $this->assertEquals(
  137. ['text' => 'Third Article Body', 'author_id' => 1, 'name' => 'mariano'],
  138. $result->fetch('assoc')
  139. );
  140. }
  141. /**
  142. * Tests it is possible to add joins to a select query
  143. *
  144. * @return void
  145. */
  146. public function testSelectWithJoins() {
  147. $query = new Query($this->connection);
  148. $result = $query
  149. ->select(['title', 'name'])
  150. ->from('articles')
  151. ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
  152. ->order(['title' => 'asc'])
  153. ->execute();
  154. $this->assertCount(3, $result);
  155. $this->assertEquals(array('title' => 'First Article', 'name' => 'mariano'), $result->fetch('assoc'));
  156. $this->assertEquals(array('title' => 'Second Article', 'name' => 'larry'), $result->fetch('assoc'));
  157. $result = $query->join('authors', [], true)->execute();
  158. $this->assertCount(12, $result, 'Cross join results in 12 records');
  159. $result = $query->join([
  160. ['table' => 'authors', 'type' => 'INNER', 'conditions' => 'author_id = authors.id']
  161. ], [], true)->execute();
  162. $this->assertCount(3, $result);
  163. $this->assertEquals(array('title' => 'First Article', 'name' => 'mariano'), $result->fetch('assoc'));
  164. $this->assertEquals(array('title' => 'Second Article', 'name' => 'larry'), $result->fetch('assoc'));
  165. }
  166. /**
  167. * Tests it is possible to add joins to a select query using array or expression as conditions
  168. *
  169. * @return void
  170. */
  171. public function testSelectWithJoinsConditions() {
  172. $query = new Query($this->connection);
  173. $result = $query
  174. ->select(['title', 'name'])
  175. ->from('articles')
  176. ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => ['author_id = a.id']])
  177. ->order(['title' => 'asc'])
  178. ->execute();
  179. $this->assertEquals(array('title' => 'First Article', 'name' => 'mariano'), $result->fetch('assoc'));
  180. $this->assertEquals(array('title' => 'Second Article', 'name' => 'larry'), $result->fetch('assoc'));
  181. $query = new Query($this->connection);
  182. $conditions = $query->newExpr()->add('author_id = a.id');
  183. $result = $query
  184. ->select(['title', 'name'])
  185. ->from('articles')
  186. ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => $conditions])
  187. ->order(['title' => 'asc'])
  188. ->execute();
  189. $this->assertEquals(array('title' => 'First Article', 'name' => 'mariano'), $result->fetch('assoc'));
  190. $this->assertEquals(array('title' => 'Second Article', 'name' => 'larry'), $result->fetch('assoc'));
  191. $query = new Query($this->connection);
  192. $time = new \DateTime('2007-03-18 10:50:00');
  193. $types = ['created' => 'datetime'];
  194. $result = $query
  195. ->select(['title', 'comment' => 'c.comment'])
  196. ->from('articles')
  197. ->join(['table' => 'comments', 'alias' => 'c', 'conditions' => ['created <=' => $time]], $types)
  198. ->execute();
  199. $this->assertEquals(['title' => 'First Article', 'comment' => 'First Comment for First Article'], $result->fetch('assoc'));
  200. }
  201. /**
  202. * Tests that joins can be aliased using array keys
  203. *
  204. * @return void
  205. */
  206. public function testSelectAliasedJoins() {
  207. $query = new Query($this->connection);
  208. $result = $query
  209. ->select(['title', 'name'])
  210. ->from('articles')
  211. ->join(['a' => 'authors'])
  212. ->order(['name' => 'desc', 'articles.id' => 'asc'])
  213. ->execute();
  214. $this->assertEquals(array('title' => 'First Article', 'name' => 'nate'), $result->fetch('assoc'));
  215. $this->assertEquals(array('title' => 'Second Article', 'name' => 'nate'), $result->fetch('assoc'));
  216. $query = new Query($this->connection);
  217. $conditions = $query->newExpr()->add('author_id = a.id');
  218. $result = $query
  219. ->select(['title', 'name'])
  220. ->from('articles')
  221. ->join(['a' => ['table' => 'authors', 'conditions' => $conditions]])
  222. ->order(['title' => 'asc'])
  223. ->execute();
  224. $this->assertEquals(array('title' => 'First Article', 'name' => 'mariano'), $result->fetch('assoc'));
  225. $this->assertEquals(array('title' => 'Second Article', 'name' => 'larry'), $result->fetch('assoc'));
  226. $query = new Query($this->connection);
  227. $time = new \DateTime('2007-03-18 10:45:23');
  228. $types = ['created' => 'datetime'];
  229. $result = $query
  230. ->select(['title', 'name' => 'c.comment'])
  231. ->from('articles')
  232. ->join(['c' => ['table' => 'comments', 'conditions' => ['created' => $time]]], $types)
  233. ->execute();
  234. $this->assertEquals(array('title' => 'First Article', 'name' => 'First Comment for First Article'), $result->fetch('assoc'));
  235. }
  236. /**
  237. * Tests it is possible to filter a query by using simple AND joined conditions
  238. *
  239. * @return void
  240. */
  241. public function testSelectSimpleWhere() {
  242. $query = new Query($this->connection);
  243. $result = $query
  244. ->select(['title'])
  245. ->from('articles')
  246. ->where(['id' => 1, 'title' => 'First Article'])
  247. ->execute();
  248. $this->assertCount(1, $result);
  249. $query = new Query($this->connection);
  250. $result = $query
  251. ->select(['title'])
  252. ->from('articles')
  253. ->where(['id' => 100], ['id' => 'integer'])
  254. ->execute();
  255. $this->assertCount(0, $result);
  256. }
  257. /**
  258. * Tests using where conditions with operators and scalar values works
  259. *
  260. * @return void
  261. */
  262. public function testSelectWhereOperators() {
  263. $query = new Query($this->connection);
  264. $result = $query
  265. ->select(['title'])
  266. ->from('articles')
  267. ->where(['id >' => 1])
  268. ->execute();
  269. $this->assertCount(2, $result);
  270. $this->assertEquals(array('title' => 'Second Article'), $result->fetch('assoc'));
  271. $query = new Query($this->connection);
  272. $result = $query
  273. ->select(['title'])
  274. ->from('articles')
  275. ->where(['id <' => 2])
  276. ->execute();
  277. $this->assertCount(1, $result);
  278. $this->assertEquals(array('title' => 'First Article'), $result->fetch('assoc'));
  279. $query = new Query($this->connection);
  280. $result = $query
  281. ->select(['title'])
  282. ->from('articles')
  283. ->where(['id <=' => 2])
  284. ->execute();
  285. $this->assertCount(2, $result);
  286. $query = new Query($this->connection);
  287. $result = $query
  288. ->select(['title'])
  289. ->from('articles')
  290. ->where(['id >=' => 1])
  291. ->execute();
  292. $this->assertCount(3, $result);
  293. $query = new Query($this->connection);
  294. $result = $query
  295. ->select(['title'])
  296. ->from('articles')
  297. ->where(['id <=' => 1])
  298. ->execute();
  299. $this->assertCount(1, $result);
  300. $query = new Query($this->connection);
  301. $result = $query
  302. ->select(['title'])
  303. ->from('articles')
  304. ->where(['id !=' => 2])
  305. ->execute();
  306. $this->assertCount(2, $result);
  307. $this->assertEquals(array('title' => 'First Article'), $result->fetch('assoc'));
  308. $query = new Query($this->connection);
  309. $result = $query
  310. ->select(['title'])
  311. ->from('articles')
  312. ->where(['title LIKE' => 'First Article'])
  313. ->execute();
  314. $this->assertCount(1, $result);
  315. $this->assertEquals(array('title' => 'First Article'), $result->fetch('assoc'));
  316. $query = new Query($this->connection);
  317. $result = $query
  318. ->select(['title'])
  319. ->from('articles')
  320. ->where(['title like' => '%Article%'])
  321. ->execute();
  322. $this->assertCount(3, $result);
  323. $query = new Query($this->connection);
  324. $result = $query
  325. ->select(['title'])
  326. ->from('articles')
  327. ->where(['title not like' => '%Article%'])
  328. ->execute();
  329. $this->assertCount(0, $result);
  330. }
  331. /**
  332. * Tests selecting with conditions and specifying types for those
  333. *
  334. * @return void
  335. **/
  336. public function testSelectWhereTypes() {
  337. $query = new Query($this->connection);
  338. $result = $query
  339. ->select(['id'])
  340. ->from('comments')
  341. ->where(['created' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime'])
  342. ->execute();
  343. $this->assertCount(1, $result);
  344. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  345. $query = new Query($this->connection);
  346. $result = $query
  347. ->select(['id'])
  348. ->from('comments')
  349. ->where(['created >' => new \DateTime('2007-03-18 10:46:00')], ['created' => 'datetime'])
  350. ->execute();
  351. $this->assertCount(5, $result);
  352. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  353. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  354. $query = new Query($this->connection);
  355. $result = $query
  356. ->select(['id'])
  357. ->from('comments')
  358. ->where(
  359. [
  360. 'created >' => new \DateTime('2007-03-18 10:40:00'),
  361. 'created <' => new \DateTime('2007-03-18 10:46:00')
  362. ],
  363. ['created' => 'datetime']
  364. )
  365. ->execute();
  366. $this->assertCount(1, $result);
  367. $this->assertEquals(array('id' => 1), $result->fetch('assoc'));
  368. $query = new Query($this->connection);
  369. $result = $query
  370. ->select(['id'])
  371. ->from('comments')
  372. ->where(
  373. [
  374. 'id' => '3something-crazy',
  375. 'created <' => new \DateTime('2013-01-01 12:00')
  376. ],
  377. ['created' => 'datetime', 'id' => 'integer']
  378. )
  379. ->execute();
  380. $this->assertCount(1, $result);
  381. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  382. $query = new Query($this->connection);
  383. $result = $query
  384. ->select(['id'])
  385. ->from('comments')
  386. ->where(
  387. [
  388. 'id' => '1something-crazy',
  389. 'created <' => new \DateTime('2013-01-01 12:00')
  390. ],
  391. ['created' => 'datetime', 'id' => 'float']
  392. )
  393. ->execute();
  394. $this->assertCount(1, $result);
  395. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  396. }
  397. /**
  398. * Tests that passing an array type to any where condition will replace
  399. * the passed array accordingly as a proper IN condition
  400. *
  401. * @return void
  402. */
  403. public function testSelectWhereArrayType() {
  404. $query = new Query($this->connection);
  405. $result = $query
  406. ->select(['id'])
  407. ->from('comments')
  408. ->where(['id' => ['1', '3']], ['id' => 'integer[]'])
  409. ->execute();
  410. $this->assertCount(2, $result);
  411. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  412. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  413. }
  414. /**
  415. * Tests that Query::orWhere() can be used to concatenate conditions with OR
  416. *
  417. * @return void
  418. **/
  419. public function testSelectOrWhere() {
  420. $query = new Query($this->connection);
  421. $result = $query
  422. ->select(['id'])
  423. ->from('comments')
  424. ->where(['created' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime'])
  425. ->orWhere(['created' => new \DateTime('2007-03-18 10:47:23')], ['created' => 'datetime'])
  426. ->execute();
  427. $this->assertCount(2, $result);
  428. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  429. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  430. }
  431. /**
  432. * Tests that Query::andWhere() can be used to concatenate conditions with AND
  433. *
  434. * @return void
  435. **/
  436. public function testSelectAndWhere() {
  437. $query = new Query($this->connection);
  438. $result = $query
  439. ->select(['id'])
  440. ->from('comments')
  441. ->where(['created' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime'])
  442. ->andWhere(['id' => 1])
  443. ->execute();
  444. $this->assertCount(1, $result);
  445. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  446. $query = new Query($this->connection);
  447. $result = $query
  448. ->select(['id'])
  449. ->from('comments')
  450. ->where(['created' => new \DateTime('2007-03-18 10:50:55')], ['created' => 'datetime'])
  451. ->andWhere(['id' => 2])
  452. ->execute();
  453. $this->assertCount(0, $result);
  454. }
  455. /**
  456. * Tests that combining Query::andWhere() and Query::orWhere() produces
  457. * correct conditions nesting
  458. *
  459. * @return void
  460. **/
  461. public function testSelectExpressionNesting() {
  462. $query = new Query($this->connection);
  463. $result = $query
  464. ->select(['id'])
  465. ->from('comments')
  466. ->where(['created' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime'])
  467. ->orWhere(['id' => 2])
  468. ->andWhere(['created >=' => new \DateTime('2007-03-18 10:40:00')], ['created' => 'datetime'])
  469. ->execute();
  470. $this->assertCount(2, $result);
  471. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  472. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  473. $query = new Query($this->connection);
  474. $result = $query
  475. ->select(['id'])
  476. ->from('comments')
  477. ->where(['created' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime'])
  478. ->orWhere(['id' => 2])
  479. ->andWhere(['created >=' => new \DateTime('2007-03-18 10:40:00')], ['created' => 'datetime'])
  480. ->orWhere(['created' => new \DateTime('2007-03-18 10:49:23')], ['created' => 'datetime'])
  481. ->execute();
  482. $this->assertCount(3, $result);
  483. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  484. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  485. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  486. }
  487. /**
  488. * Tests that Query::orWhere() can be used without calling where() before
  489. *
  490. * @return void
  491. **/
  492. public function testSelectOrWhereNoPreviousCondition() {
  493. $query = new Query($this->connection);
  494. $result = $query
  495. ->select(['id'])
  496. ->from('comments')
  497. ->orWhere(['created' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime'])
  498. ->orWhere(['created' => new \DateTime('2007-03-18 10:47:23')], ['created' => 'datetime'])
  499. ->execute();
  500. $this->assertCount(2, $result);
  501. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  502. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  503. }
  504. /**
  505. * Tests that Query::andWhere() can be used without calling where() before
  506. *
  507. * @return void
  508. **/
  509. public function testSelectAndWhereNoPreviousCondition() {
  510. $query = new Query($this->connection);
  511. $result = $query
  512. ->select(['id'])
  513. ->from('comments')
  514. ->andWhere(['created' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime'])
  515. ->andWhere(['id' => 1])
  516. ->execute();
  517. $this->assertCount(1, $result);
  518. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  519. }
  520. /**
  521. * Tests that it is possible to pass a closure to where() to build a set of
  522. * conditions and return the expression to be used
  523. *
  524. * @return void
  525. */
  526. public function testSelectWhereUsingClosure() {
  527. $query = new Query($this->connection);
  528. $result = $query
  529. ->select(['id'])
  530. ->from('comments')
  531. ->where(function($exp) {
  532. return $exp->eq('id', 1);
  533. })
  534. ->execute();
  535. $this->assertCount(1, $result);
  536. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  537. $query = new Query($this->connection);
  538. $result = $query
  539. ->select(['id'])
  540. ->from('comments')
  541. ->where(function($exp) {
  542. return $exp
  543. ->eq('id', 1)
  544. ->eq('created', new \DateTime('2007-03-18 10:45:23'), 'datetime');
  545. })
  546. ->execute();
  547. $this->assertCount(1, $result);
  548. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  549. $query = new Query($this->connection);
  550. $result = $query
  551. ->select(['id'])
  552. ->from('comments')
  553. ->where(function($exp) {
  554. return $exp
  555. ->eq('id', 1)
  556. ->eq('created', new \DateTime('2021-12-30 15:00'), 'datetime');
  557. })
  558. ->execute();
  559. $this->assertCount(0, $result);
  560. }
  561. /**
  562. * Tests that it is possible to pass a closure to andWhere() to build a set of
  563. * conditions and return the expression to be used
  564. *
  565. * @return void
  566. */
  567. public function testSelectAndWhereUsingClosure() {
  568. $query = new Query($this->connection);
  569. $result = $query
  570. ->select(['id'])
  571. ->from('comments')
  572. ->where(['id' => '1'])
  573. ->andWhere(function($exp) {
  574. return $exp->eq('created', new \DateTime('2007-03-18 10:45:23'), 'datetime');
  575. })
  576. ->execute();
  577. $this->assertCount(1, $result);
  578. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  579. $query = new Query($this->connection);
  580. $result = $query
  581. ->select(['id'])
  582. ->from('comments')
  583. ->where(['id' => '1'])
  584. ->andWhere(function($exp) {
  585. return $exp->eq('created', new \DateTime('2022-12-21 12:00'), 'datetime');
  586. })
  587. ->execute();
  588. $this->assertCount(0, $result);
  589. }
  590. /**
  591. * Tests that it is possible to pass a closure to orWhere() to build a set of
  592. * conditions and return the expression to be used
  593. *
  594. * @return void
  595. */
  596. public function testSelectOrWhereUsingClosure() {
  597. $query = new Query($this->connection);
  598. $result = $query
  599. ->select(['id'])
  600. ->from('comments')
  601. ->where(['id' => '1'])
  602. ->orWhere(function($exp) {
  603. return $exp->eq('created', new \DateTime('2007-03-18 10:47:23'), 'datetime');
  604. })
  605. ->execute();
  606. $this->assertCount(2, $result);
  607. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  608. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  609. $query = new Query($this->connection);
  610. $result = $query
  611. ->select(['id'])
  612. ->from('comments')
  613. ->where(['id' => '1'])
  614. ->orWhere(function($exp) {
  615. return $exp
  616. ->eq('created', new \DateTime('2012-12-22 12:00'), 'datetime')
  617. ->eq('id', 3);
  618. })
  619. ->execute();
  620. $this->assertCount(1, $result);
  621. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  622. }
  623. /**
  624. * Tests using where conditions with operator methods
  625. *
  626. * @return void
  627. */
  628. public function testSelectWhereOperatorMethods() {
  629. $query = new Query($this->connection);
  630. $result = $query
  631. ->select(['title'])
  632. ->from('articles')
  633. ->where(function($exp) {
  634. return $exp->gt('id', 1);
  635. })
  636. ->execute();
  637. $this->assertCount(2, $result);
  638. $this->assertEquals(array('title' => 'Second Article'), $result->fetch('assoc'));
  639. $query = new Query($this->connection);
  640. $result = $query->select(['title'])
  641. ->from('articles')
  642. ->where(function($exp) {
  643. return $exp->lt('id', 2);
  644. })
  645. ->execute();
  646. $this->assertCount(1, $result);
  647. $this->assertEquals(array('title' => 'First Article'), $result->fetch('assoc'));
  648. $query = new Query($this->connection);
  649. $result = $query->select(['title'])
  650. ->from('articles')
  651. ->where(function($exp) {
  652. return $exp->lte('id', 2);
  653. })
  654. ->execute();
  655. $this->assertCount(2, $result);
  656. $query = new Query($this->connection);
  657. $result = $query
  658. ->select(['title'])
  659. ->from('articles')
  660. ->where(function($exp) {
  661. return $exp->gte('id', 1);
  662. })
  663. ->execute();
  664. $this->assertCount(3, $result);
  665. $query = new Query($this->connection);
  666. $result = $query
  667. ->select(['title'])
  668. ->from('articles')
  669. ->where(function($exp) {
  670. return $exp->lte('id', 1);
  671. })
  672. ->execute();
  673. $this->assertCount(1, $result);
  674. $query = new Query($this->connection);
  675. $result = $query
  676. ->select(['title'])
  677. ->from('articles')
  678. ->where(function($exp) {
  679. return $exp->notEq('id', 2);
  680. })
  681. ->execute();
  682. $this->assertCount(2, $result);
  683. $this->assertEquals(array('title' => 'First Article'), $result->fetch('assoc'));
  684. $query = new Query($this->connection);
  685. $result = $query
  686. ->select(['title'])
  687. ->from('articles')
  688. ->where(function($exp) {
  689. return $exp->like('title', 'First Article');
  690. })
  691. ->execute();
  692. $this->assertCount(1, $result);
  693. $this->assertEquals(array('title' => 'First Article'), $result->fetch('assoc'));
  694. $query = new Query($this->connection);
  695. $result = $query
  696. ->select(['title'])
  697. ->from('articles')
  698. ->where(function($exp) {
  699. return $exp->like('title', '%Article%');
  700. })
  701. ->execute();
  702. $this->assertCount(3, $result);
  703. $query = new Query($this->connection);
  704. $result = $query
  705. ->select(['title'])
  706. ->from('articles')
  707. ->where(function($exp) {
  708. return $exp->notLike('title', '%Article%');
  709. })
  710. ->execute();
  711. $this->assertCount(0, $result);
  712. $query = new Query($this->connection);
  713. $result = $query
  714. ->select(['id'])
  715. ->from('comments')
  716. ->where(function($exp) {
  717. return $exp->isNull('published');
  718. })
  719. ->execute();
  720. $this->assertCount(0, $result);
  721. $query = new Query($this->connection);
  722. $result = $query
  723. ->select(['id'])
  724. ->from('comments')
  725. ->where(function($exp) {
  726. return $exp->isNotNull('published');
  727. })
  728. ->execute();
  729. $this->assertCount(6, $result);
  730. $query = new Query($this->connection);
  731. $result = $query
  732. ->select(['id'])
  733. ->from('comments')
  734. ->where(function($exp) {
  735. return $exp->in('published', ['Y', 'N']);
  736. })
  737. ->execute();
  738. $this->assertCount(6, $result);
  739. $query = new Query($this->connection);
  740. $result = $query
  741. ->select(['id'])
  742. ->from('comments')
  743. ->where(function($exp) {
  744. return $exp->in(
  745. 'created',
  746. [new \DateTime('2007-03-18 10:45:23'), new \DateTime('2007-03-18 10:47:23')],
  747. 'datetime'
  748. );
  749. })
  750. ->execute();
  751. $this->assertCount(2, $result);
  752. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  753. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  754. $query = new Query($this->connection);
  755. $result = $query
  756. ->select(['id'])
  757. ->from('comments')
  758. ->where(function($exp) {
  759. return $exp->notIn(
  760. 'created',
  761. [new \DateTime('2007-03-18 10:45:23'), new \DateTime('2007-03-18 10:47:23')],
  762. 'datetime'
  763. );
  764. })
  765. ->execute();
  766. $this->assertCount(4, $result);
  767. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  768. }
  769. /**
  770. * Tests nesting query expressions both using arrays and closures
  771. *
  772. * @return void
  773. **/
  774. public function testSelectExpressionComposition() {
  775. $query = new Query($this->connection);
  776. $result = $query
  777. ->select(['id'])
  778. ->from('comments')
  779. ->where(function($exp) {
  780. $and = $exp->and_(['id' => 2, 'id >' => 1]);
  781. return $exp->add($and);
  782. })
  783. ->execute();
  784. $this->assertCount(1, $result);
  785. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  786. $query = new Query($this->connection);
  787. $result = $query
  788. ->select(['id'])
  789. ->from('comments')
  790. ->where(function($exp) {
  791. $and = $exp->and_(['id' => 2, 'id <' => 2]);
  792. return $exp->add($and);
  793. })
  794. ->execute();
  795. $this->assertCount(0, $result);
  796. $query = new Query($this->connection);
  797. $result = $query
  798. ->select(['id'])
  799. ->from('comments')
  800. ->where(function($exp) {
  801. $and = $exp->and_(function($and) {
  802. return $and->eq('id', 1)->gt('id', 0);
  803. });
  804. return $exp->add($and);
  805. })
  806. ->execute();
  807. $this->assertCount(1, $result);
  808. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  809. $query = new Query($this->connection);
  810. $result = $query
  811. ->select(['id'])
  812. ->from('comments')
  813. ->where(function($exp) {
  814. $or = $exp->or_(['id' => 1]);
  815. $and = $exp->and_(['id >' => 2, 'id <' => 4]);
  816. return $or->add($and);
  817. })
  818. ->execute();
  819. $this->assertCount(2, $result);
  820. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  821. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  822. $query = new Query($this->connection);
  823. $result = $query
  824. ->select(['id'])
  825. ->from('comments')
  826. ->where(function($exp) {
  827. $or = $exp->or_(function($or) {
  828. return $or->eq('id', 1)->eq('id', 2);
  829. });
  830. return $or;
  831. })
  832. ->execute();
  833. $this->assertCount(2, $result);
  834. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  835. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  836. }
  837. /**
  838. * Tests that conditions can be nested with an unary operator using the array notation
  839. * and the not() method
  840. *
  841. * @return void
  842. **/
  843. public function testSelectWhereNot() {
  844. $query = new Query($this->connection);
  845. $result = $query
  846. ->select(['id'])
  847. ->from('comments')
  848. ->where(function($exp) {
  849. return $exp->not(
  850. $exp->and_(['id' => 2, 'created' => new \DateTime('2007-03-18 10:47:23')], ['created' => 'datetime'])
  851. );
  852. })
  853. ->execute();
  854. $this->assertCount(5, $result);
  855. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  856. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  857. $query = new Query($this->connection);
  858. $result = $query
  859. ->select(['id'])
  860. ->from('comments')
  861. ->where(function($exp) {
  862. return $exp->not(
  863. $exp->and_(['id' => 2, 'created' => new \DateTime('2012-12-21 12:00')], ['created' => 'datetime'])
  864. );
  865. })
  866. ->execute();
  867. $this->assertCount(6, $result);
  868. $query = new Query($this->connection);
  869. $result = $query
  870. ->select(['id'])
  871. ->from('articles')
  872. ->where([
  873. 'not' => ['or' => ['id' => 1, 'id >' => 2], 'id' => 3]
  874. ])
  875. ->execute();
  876. $this->assertCount(2, $result);
  877. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  878. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  879. }
  880. /**
  881. * Tests order() method both with simple fields and expressions
  882. *
  883. * @return void
  884. **/
  885. public function testSelectOrderBy() {
  886. $query = new Query($this->connection);
  887. $result = $query
  888. ->select(['id'])
  889. ->from('articles')
  890. ->order(['id' => 'desc'])
  891. ->execute();
  892. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  893. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  894. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  895. $result = $query->order(['id' => 'asc'])->execute();
  896. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  897. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  898. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  899. $result = $query->order(['title' => 'asc'])->execute();
  900. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  901. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  902. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  903. $result = $query->order(['title' => 'asc'], true)->execute();
  904. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  905. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  906. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  907. $result = $query->order(['title' => 'asc', 'published' => 'asc'], true)
  908. ->execute();
  909. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  910. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  911. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  912. $expression = $query->newExpr()
  913. ->add(['(id + :offset) % 2 = 0']);
  914. $result = $query
  915. ->order([$expression, 'id' => 'desc'], true)
  916. ->bind(':offset', 1, null)
  917. ->execute();
  918. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  919. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  920. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  921. $result = $query
  922. ->order($expression, true)
  923. ->order(['id' => 'asc'])
  924. ->bind(':offset', 1, null)
  925. ->execute();
  926. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  927. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  928. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  929. }
  930. /**
  931. * Tests that group by fields can be passed similar to select fields
  932. * and that it sends the correct query to the database
  933. *
  934. * @return void
  935. **/
  936. public function testSelectGroup() {
  937. $query = new Query($this->connection);
  938. $result = $query
  939. ->select(['total' => 'count(author_id)', 'author_id'])
  940. ->from('articles')
  941. ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
  942. ->group('author_id')
  943. ->execute();
  944. $expected = [['total' => 2, 'author_id' => 1], ['total' => '1', 'author_id' => 3]];
  945. $this->assertEquals($expected, $result->fetchAll('assoc'));
  946. $result = $query->select(['total' => 'count(title)', 'name'], true)
  947. ->group(['name'], true)
  948. ->order(['total' => 'asc'])
  949. ->execute();
  950. $expected = [['total' => 1, 'name' => 'larry'], ['total' => 2, 'name' => 'mariano']];
  951. $this->assertEquals($expected, $result->fetchAll('assoc'));
  952. $result = $query->select(['articles.id'])
  953. ->group(['articles.id'])
  954. ->execute();
  955. $this->assertCount(3, $result);
  956. }
  957. /**
  958. * Tests that it is possible to select distinct rows, even filtering by one column
  959. * this is testing that there is an specific implementation for DISTINCT ON
  960. *
  961. * @return void
  962. */
  963. public function testSelectDistinct() {
  964. $query = new Query($this->connection);
  965. $result = $query
  966. ->select(['author_id'])
  967. ->from(['a' => 'articles'])
  968. ->execute();
  969. $this->assertCount(3, $result);
  970. $result = $query->distinct()->execute();
  971. $this->assertCount(2, $result);
  972. $result = $query->select(['id'])->distinct(false)->execute();
  973. $this->assertCount(3, $result);
  974. $result = $query->select(['id'])->distinct(['author_id'])->execute();
  975. $this->assertCount(2, $result);
  976. }
  977. /**
  978. * Tests that having() behaves pretty much the same as the where() method
  979. *
  980. * @return void
  981. */
  982. public function testSelectHaving() {
  983. $query = new Query($this->connection);
  984. $result = $query
  985. ->select(['total' => 'count(author_id)', 'author_id'])
  986. ->from('articles')
  987. ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
  988. ->group('author_id')
  989. ->having(['count(author_id) <' => 2], ['count(author_id)' => 'integer'])
  990. ->execute();
  991. $expected = [['total' => 1, 'author_id' => 3]];
  992. $this->assertEquals($expected, $result->fetchAll('assoc'));
  993. $result = $query->having(['count(author_id)' => 2], ['count(author_id)' => 'integer'], true)
  994. ->execute();
  995. $expected = [['total' => 2, 'author_id' => 1]];
  996. $this->assertEquals($expected, $result->fetchAll('assoc'));
  997. $result = $query->having(function($e) {
  998. return $e->add('count(author_id) = 1 + 1');
  999. }, [], true)
  1000. ->execute();
  1001. $expected = [['total' => 2, 'author_id' => 1]];
  1002. $this->assertEquals($expected, $result->fetchAll('assoc'));
  1003. }
  1004. /**
  1005. * Tests that Query::orHaving() can be used to concatenate conditions with OR
  1006. * in the having clause
  1007. *
  1008. * @return void
  1009. */
  1010. public function testSelectOrHaving() {
  1011. $query = new Query($this->connection);
  1012. $result = $query
  1013. ->select(['total' => 'count(author_id)', 'author_id'])
  1014. ->from('articles')
  1015. ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
  1016. ->group('author_id')
  1017. ->having(['count(author_id) >' => 2], ['count(author_id)' => 'integer'])
  1018. ->orHaving(['count(author_id) <' => 2], ['count(author_id)' => 'integer'])
  1019. ->execute();
  1020. $expected = [['total' => 1, 'author_id' => 3]];
  1021. $this->assertEquals($expected, $result->fetchAll('assoc'));
  1022. $query = new Query($this->connection);
  1023. $result = $query
  1024. ->select(['total' => 'count(author_id)', 'author_id'])
  1025. ->from('articles')
  1026. ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
  1027. ->group('author_id')
  1028. ->having(['count(author_id) >' => 2], ['count(author_id)' => 'integer'])
  1029. ->orHaving(['count(author_id) <=' => 2], ['count(author_id)' => 'integer'])
  1030. ->execute();
  1031. $expected = [['total' => 2, 'author_id' => 1], ['total' => 1, 'author_id' => 3]];
  1032. $this->assertEquals($expected, $result->fetchAll('assoc'));
  1033. $query = new Query($this->connection);
  1034. $result = $query
  1035. ->select(['total' => 'count(author_id)', 'author_id'])
  1036. ->from('articles')
  1037. ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
  1038. ->group('author_id')
  1039. ->having(['count(author_id) >' => 2], ['count(author_id)' => 'integer'])
  1040. ->orHaving(function($e) {
  1041. return $e->add('count(author_id) = 1 + 1');
  1042. })
  1043. ->execute();
  1044. $expected = [['total' => 2, 'author_id' => 1]];
  1045. $this->assertEquals($expected, $result->fetchAll('assoc'));
  1046. }
  1047. /**
  1048. * Tests that Query::andHaving() can be used to concatenate conditions with AND
  1049. * in the having clause
  1050. *
  1051. * @return void
  1052. */
  1053. public function testSelectAndHaving() {
  1054. $query = new Query($this->connection);
  1055. $result = $query
  1056. ->select(['total' => 'count(author_id)', 'author_id'])
  1057. ->from('articles')
  1058. ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
  1059. ->group('author_id')
  1060. ->having(['count(author_id) >' => 2], ['count(author_id)' => 'integer'])
  1061. ->andHaving(['count(author_id) <' => 2], ['count(author_id)' => 'integer'])
  1062. ->execute();
  1063. $this->assertCount(0, $result);
  1064. $query = new Query($this->connection);
  1065. $result = $query
  1066. ->select(['total' => 'count(author_id)', 'author_id'])
  1067. ->from('articles')
  1068. ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
  1069. ->group('author_id')
  1070. ->having(['count(author_id)' => 2], ['count(author_id)' => 'integer'])
  1071. ->andHaving(['count(author_id) >' => 1], ['count(author_id)' => 'integer'])
  1072. ->execute();
  1073. $expected = [['total' => 2, 'author_id' => 1]];
  1074. $this->assertEquals($expected, $result->fetchAll('assoc'));
  1075. $query = new Query($this->connection);
  1076. $result = $query
  1077. ->select(['total' => 'count(author_id)', 'author_id'])
  1078. ->from('articles')
  1079. ->join(['table' => 'authors', 'alias' => 'a', 'conditions' => 'author_id = a.id'])
  1080. ->group('author_id')
  1081. ->andHaving(function($e) {
  1082. return $e->add('count(author_id) = 2 - 1');
  1083. })
  1084. ->execute();
  1085. $expected = [['total' => 1, 'author_id' => 3]];
  1086. $this->assertEquals($expected, $result->fetchAll('assoc'));
  1087. }
  1088. /**
  1089. * Tests selecting rows using a limit clause
  1090. *
  1091. * @return void
  1092. **/
  1093. public function testSelectLimit() {
  1094. $query = new Query($this->connection);
  1095. $result = $query->select('id')->from('articles')->limit(1)->execute();
  1096. $this->assertCount(1, $result);
  1097. $result = $query->limit(null)->execute();
  1098. $this->assertCount(3, $result);
  1099. $result = $query->limit(2)->execute();
  1100. $this->assertCount(2, $result);
  1101. $result = $query->limit(3)->execute();
  1102. $this->assertCount(3, $result);
  1103. }
  1104. /**
  1105. * Tests selecting rows combining a limit and offset clause
  1106. *
  1107. * @return void
  1108. **/
  1109. public function testSelectOffset() {
  1110. $query = new Query($this->connection);
  1111. $result = $query->select('id')->from('comments')
  1112. ->limit(1)
  1113. ->offset(0)->execute();
  1114. $this->assertCount(1, $result);
  1115. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  1116. $result = $query->offset(1)->execute();
  1117. $this->assertCount(1, $result);
  1118. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  1119. $result = $query->offset(2)->execute();
  1120. $this->assertCount(1, $result);
  1121. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  1122. $query = new Query($this->connection);
  1123. $result = $query->select('id')->from('articles')
  1124. ->order(['id' => 'desc'])
  1125. ->limit(1)
  1126. ->offset(0)->execute();
  1127. $this->assertCount(1, $result);
  1128. $this->assertEquals(['id' => 3], $result->fetch('assoc'));
  1129. $result = $query->limit(2)->offset(1)->execute();
  1130. $this->assertCount(2, $result);
  1131. $this->assertEquals(['id' => 2], $result->fetch('assoc'));
  1132. $this->assertEquals(['id' => 1], $result->fetch('assoc'));
  1133. }
  1134. /**
  1135. * Tests that Query objects can be included inside the select clause
  1136. * and be used as a normal field, including binding any passed parameter
  1137. *
  1138. * @return void
  1139. */
  1140. public function testSubqueryInSelect() {
  1141. $query = new Query($this->connection);
  1142. $subquery = (new Query($this->connection))
  1143. ->select('name')
  1144. ->from(['b' => 'authors'])
  1145. ->where(['b.id = a.id']);
  1146. $result = $query
  1147. ->select(['id', 'name' => $subquery])
  1148. ->from(['a' => 'comments'])->execute();
  1149. $expected = [
  1150. ['id' => 1, 'name' => 'mariano'],
  1151. ['id' => 2, 'name' => 'nate'],
  1152. ['id' => 3, 'name' => 'larry'],
  1153. ['id' => 4, 'name' => 'garrett'],
  1154. ['id' => 5, 'name' => null],
  1155. ['id' => 6, 'name' => null],
  1156. ];
  1157. $this->assertEquals($expected, $result->fetchAll('assoc'));
  1158. $query = new Query($this->connection);
  1159. $subquery = (new Query($this->connection))
  1160. ->select('name')
  1161. ->from(['b' => 'authors'])
  1162. ->where(['name' => 'mariano'], ['name' => 'string']);
  1163. $result = $query
  1164. ->select(['id', 'name' => $subquery])
  1165. ->from(['a' => 'articles'])->execute();
  1166. $expected = [
  1167. ['id' => 1, 'name' => 'mariano'],
  1168. ['id' => 2, 'name' => 'mariano'],
  1169. ['id' => 3, 'name' => 'mariano'],
  1170. ];
  1171. $this->assertEquals($expected, $result->fetchAll('assoc'));
  1172. }
  1173. /**
  1174. * Tests that Query objects can be included inside the from clause
  1175. * and be used as a normal table, including binding any passed parameter
  1176. *
  1177. * @return void
  1178. */
  1179. public function testSuqueryInFrom() {
  1180. $query = new Query($this->connection);
  1181. $subquery = (new Query($this->connection))
  1182. ->select(['id', 'comment'])
  1183. ->from('comments')
  1184. ->where(['created >' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime']);
  1185. $result = $query
  1186. ->select(['comment'])
  1187. ->from(['b' => $subquery])
  1188. ->where(['id !=' => 3])
  1189. ->execute();
  1190. $expected = [
  1191. ['comment' => 'Second Comment for First Article'],
  1192. ['comment' => 'Fourth Comment for First Article'],
  1193. ['comment' => 'First Comment for Second Article'],
  1194. ['comment' => 'Second Comment for Second Article'],
  1195. ];
  1196. $this->assertEquals($expected, $result->fetchAll('assoc'));
  1197. }
  1198. /**
  1199. * Tests that Query objects can be included inside the where clause
  1200. * and be used as a normal condition, including binding any passed parameter
  1201. *
  1202. * @return void
  1203. */
  1204. public function testSubqueryInWhere() {
  1205. $query = new Query($this->connection);
  1206. $subquery = (new Query($this->connection))
  1207. ->select(['id'])
  1208. ->from('authors')
  1209. ->where(['id' => 1]);
  1210. $result = $query
  1211. ->select(['name'])
  1212. ->from(['authors'])
  1213. ->where(['id !=' => $subquery])
  1214. ->execute();
  1215. $expected = [
  1216. ['name' => 'nate'],
  1217. ['name' => 'larry'],
  1218. ['name' => 'garrett'],
  1219. ];
  1220. $this->assertEquals($expected, $result->fetchAll('assoc'));
  1221. $query = new Query($this->connection);
  1222. $subquery = (new Query($this->connection))
  1223. ->select(['id'])
  1224. ->from('comments')
  1225. ->where(['created >' => new \DateTime('2007-03-18 10:45:23')], ['created' => 'datetime']);
  1226. $result = $query
  1227. ->select(['name'])
  1228. ->from(['authors'])
  1229. ->where(['id not in' => $subquery])
  1230. ->execute();
  1231. $expected = [
  1232. ['name' => 'mariano'],
  1233. ];
  1234. $this->assertEquals($expected, $result->fetchAll('assoc'));
  1235. }
  1236. /**
  1237. * Tests that it is possible to use a subquery in a join clause
  1238. *
  1239. * @return void
  1240. */
  1241. public function testSubqueyInJoin() {
  1242. $subquery = (new Query($this->connection))->select('*')->from('authors');
  1243. $query = new Query($this->connection);
  1244. $result = $query
  1245. ->select(['title', 'name'])
  1246. ->from('articles')
  1247. ->join(['b' => $subquery])
  1248. ->execute();
  1249. $this->assertCount(self::ARTICLE_COUNT * self::AUTHOR_COUNT, $result, 'Cross join causes multiplication');
  1250. $subquery->where(['id' => 1]);
  1251. $result = $query->execute();
  1252. $this->assertCount(3, $result);
  1253. $query->join(['b' => ['table' => $subquery, 'conditions' => ['b.id = articles.id']]], [], true);
  1254. $result = $query->execute();
  1255. $this->assertCount(1, $result);
  1256. }
  1257. /**
  1258. * Tests that it is possible to one or multiple UNION statements in a query
  1259. *
  1260. * @return void
  1261. */
  1262. public function testUnion() {
  1263. $union = (new Query($this->connection))->select(['id', 'title'])->from(['a' => 'articles']);
  1264. $query = new Query($this->connection);
  1265. $result = $query->select(['id', 'comment'])
  1266. ->from(['c' => 'comments'])
  1267. ->union($union)
  1268. ->execute();
  1269. $this->assertCount(self::COMMENT_COUNT + self::ARTICLE_COUNT, $result);
  1270. $rows = $result->fetchAll();
  1271. $union->select(['foo' => 'id', 'bar' => 'title']);
  1272. $union = (new Query($this->connection))
  1273. ->select(['id', 'name', 'other' => 'id', 'nameish' => 'name'])
  1274. ->from(['b' => 'authors'])
  1275. ->where(['id ' => 1])
  1276. ->order(['id' => 'desc']);
  1277. $query->select(['foo' => 'id', 'bar' => 'comment'])->union($union);
  1278. $result = $query->execute();
  1279. $this->assertCount(self::COMMENT_COUNT + self::AUTHOR_COUNT, $result);
  1280. $this->assertNotEquals($rows, $result->fetchAll());
  1281. $union = (new Query($this->connection))
  1282. ->select(['id', 'title'])
  1283. ->from(['c' => 'articles']);
  1284. $query->select(['id', 'comment'], true)->union($union, false, true);
  1285. $result = $query->execute();
  1286. $this->assertCount(self::COMMENT_COUNT + self::ARTICLE_COUNT, $result);
  1287. $this->assertEquals($rows, $result->fetchAll());
  1288. }
  1289. /**
  1290. * Tests that UNION ALL can be built by setting the second param of union() to true
  1291. *
  1292. * @return void
  1293. */
  1294. public function testUnionAll() {
  1295. $union = (new Query($this->connection))->select(['id', 'title'])->from(['a' => 'articles']);
  1296. $query = new Query($this->connection);
  1297. $result = $query->select(['id', 'comment'])
  1298. ->from(['c' => 'comments'])
  1299. ->union($union)
  1300. ->execute();
  1301. $this->assertCount(self::ARTICLE_COUNT + self::COMMENT_COUNT, $result);
  1302. $rows = $result->fetchAll();
  1303. $union->select(['foo' => 'id', 'bar' => 'title']);
  1304. $union = (new Query($this->connection))
  1305. ->select(['id', 'name', 'other' => 'id', 'nameish' => 'name'])
  1306. ->from(['b' => 'authors'])
  1307. ->where(['id ' => 1])
  1308. ->order(['id' => 'desc']);
  1309. $query->select(['foo' => 'id', 'bar' => 'comment'])->union($union, true);
  1310. $result = $query->execute();
  1311. $this->assertCount(1 + self::COMMENT_COUNT + self::ARTICLE_COUNT, $result);
  1312. $this->assertNotEquals($rows, $result->fetchAll());
  1313. }
  1314. /**
  1315. * Tests stacking decorators for results and resetting the list of decorators
  1316. *
  1317. * @return void
  1318. */
  1319. public function testDecorateResults() {
  1320. $query = new Query($this->connection);
  1321. $result = $query
  1322. ->select(['id', 'title'])
  1323. ->from('articles')
  1324. ->order(['id' => 'ASC'])
  1325. ->decorateResults(function($row) {
  1326. $row['modified_id'] = $row['id'] + 1;
  1327. return $row;
  1328. })
  1329. ->execute();
  1330. while ($row = $result->fetch('assoc')) {
  1331. $this->assertEquals($row['id'] + 1, $row['modified_id']);
  1332. }
  1333. $result = $query->decorateResults(function($row) {
  1334. $row['modified_id']--;
  1335. return $row;
  1336. })->execute();
  1337. while ($row = $result->fetch('assoc')) {
  1338. $this->assertEquals($row['id'], $row['modified_id']);
  1339. }
  1340. $result = $query
  1341. ->decorateResults(function($row) {
  1342. $row['foo'] = 'bar';
  1343. return $row;
  1344. }, true)
  1345. ->execute();
  1346. while ($row = $result->fetch('assoc')) {
  1347. $this->assertEquals('bar', $row['foo']);
  1348. $this->assertArrayNotHasKey('modified_id', $row);
  1349. }
  1350. $results = $query->decorateResults(null, true)->execute();
  1351. while ($row = $result->fetch('assoc')) {
  1352. $this->assertArrayNotHasKey('foo', $row);
  1353. $this->assertArrayNotHasKey('modified_id', $row);
  1354. }
  1355. }
  1356. /**
  1357. * Test a basic delete using from()
  1358. *
  1359. * @return void
  1360. */
  1361. public function testDeleteWithFrom() {
  1362. $query = new Query($this->connection);
  1363. $query->delete()
  1364. ->from('authors')
  1365. ->where('1 = 1');
  1366. $result = $query->sql();
  1367. $this->assertContains('DELETE FROM authors', $result);
  1368. $result = $query->execute();
  1369. $this->assertInstanceOf('Cake\Database\StatementInterface', $result);
  1370. $this->assertCount(self::AUTHOR_COUNT, $result);
  1371. }
  1372. /**
  1373. * Test a basic delete with no from() call.
  1374. *
  1375. * @return void
  1376. */
  1377. public function testDeleteNoFrom() {
  1378. $query = new Query($this->connection);
  1379. $query->delete('authors')
  1380. ->where('1 = 1');
  1381. $result = $query->sql();
  1382. $this->assertContains('DELETE FROM authors ', $result);
  1383. $result = $query->execute();
  1384. $this->assertInstanceOf('Cake\Database\StatementInterface', $result);
  1385. $this->assertCount(self::AUTHOR_COUNT, $result);
  1386. }
  1387. /**
  1388. * Test setting select() & delete() modes.
  1389. *
  1390. * @return void
  1391. */
  1392. public function testSelectAndDeleteOnSameQuery() {
  1393. $query = new Query($this->connection);
  1394. $result = $query->select()
  1395. ->delete('authors')
  1396. ->where('1 = 1');
  1397. $result = $query->sql();
  1398. $this->assertContains('DELETE FROM authors', $result);
  1399. $this->assertContains('authors WHERE 1 = 1', $result);
  1400. }
  1401. /**
  1402. * Test a simple update.
  1403. *
  1404. * @return void
  1405. */
  1406. public function testUpdateSimple() {
  1407. $query = new Query($this->connection);
  1408. $query->update('authors')
  1409. ->set('name', 'mark')
  1410. ->where(['id' => 1]);
  1411. $result = $query->sql();
  1412. $this->assertContains('UPDATE authors SET name = :', $result);
  1413. $result = $query->execute();
  1414. $this->assertCount(1, $result);
  1415. }
  1416. /**
  1417. * Test update with multiple fields.
  1418. *
  1419. * @return void
  1420. */
  1421. public function testUpdateMultipleFields() {
  1422. $query = new Query($this->connection);
  1423. $query->update('articles')
  1424. ->set('title', 'mark', 'string')
  1425. ->set('body', 'some text', 'string')
  1426. ->where(['id' => 1]);
  1427. $result = $query->sql();
  1428. $this->assertEquals(
  1429. 'UPDATE articles SET title = :c0 , body = :c1 WHERE id = :c2',
  1430. $result
  1431. );
  1432. $result = $query->execute();
  1433. $this->assertCount(1, $result);
  1434. }
  1435. /**
  1436. * Test updating multiple fields with an array.
  1437. *
  1438. * @return void
  1439. */
  1440. public function testUpdateMultipleFieldsArray() {
  1441. $query = new Query($this->connection);
  1442. $query->update('articles')
  1443. ->set([
  1444. 'title' => 'mark',
  1445. 'body' => 'some text'
  1446. ], ['title' => 'string', 'body' => 'string'])
  1447. ->where(['id' => 1]);
  1448. $result = $query->sql();
  1449. $this->assertRegExp(
  1450. '/UPDATE articles SET title = :[0-9a-z]+ , body = :[0-9a-z]+/',
  1451. $result
  1452. );
  1453. $this->assertContains('WHERE id = :', $result);
  1454. $result = $query->execute();
  1455. $this->assertCount(1, $result);
  1456. }
  1457. /**
  1458. * Test updates with an expression.
  1459. *
  1460. * @return void
  1461. */
  1462. public function testUpdateWithExpression() {
  1463. $query = new Query($this->connection);
  1464. $expr = $query->newExpr();
  1465. $expr->add('title = author_id');
  1466. $query->update('articles')
  1467. ->set($expr)
  1468. ->where(['id' => 1]);
  1469. $result = $query->sql();
  1470. $this->assertContains(
  1471. 'UPDATE articles SET title = author_id WHERE id = :',
  1472. $result
  1473. );
  1474. $result = $query->execute();
  1475. $this->assertCount(1, $result);
  1476. }
  1477. /**
  1478. * You cannot call values() before insert() it causes all sorts of pain.
  1479. *
  1480. * @expectedException Cake\Error\Exception
  1481. * @return void
  1482. */
  1483. public function testInsertValuesBeforeInsertFailure() {
  1484. $query = new Query($this->connection);
  1485. $query->select('*')->values([
  1486. 'id' => 1,
  1487. 'title' => 'mark',
  1488. 'body' => 'test insert'
  1489. ]);
  1490. }
  1491. /**
  1492. * Test inserting a single row.
  1493. *
  1494. * @return void
  1495. */
  1496. public function testInsertSimple() {
  1497. $query = new Query($this->connection);
  1498. $query->insert('articles', ['title', 'body'])
  1499. ->values([
  1500. 'title' => 'mark',
  1501. 'body' => 'test insert'
  1502. ]);
  1503. $result = $query->sql();
  1504. $this->assertEquals(
  1505. 'INSERT INTO articles (title, body) VALUES (?, ?)',
  1506. $result
  1507. );
  1508. $result = $query->execute();
  1509. $this->assertCount(1, $result, '1 row should be inserted');
  1510. $expected = [
  1511. [
  1512. 'id' => 4,
  1513. 'author_id' => null,
  1514. 'title' => 'mark',
  1515. 'body' => 'test insert',
  1516. 'published' => 'N',
  1517. ]
  1518. ];
  1519. $this->assertTable('articles', 1, $expected, ['id >=' => 4]);
  1520. }
  1521. /**
  1522. * Test an insert when not all the listed fields are provided.
  1523. * Columns should be matched up where possible.
  1524. *
  1525. * @return void
  1526. */
  1527. public function testInsertSparseRow() {
  1528. $query = new Query($this->connection);
  1529. $query->insert('articles', ['title', 'body'])
  1530. ->values([
  1531. 'title' => 'mark',
  1532. ]);
  1533. $result = $query->sql();
  1534. $this->assertEquals(
  1535. 'INSERT INTO articles (title, body) VALUES (?, ?)',
  1536. $result
  1537. );
  1538. $result = $query->execute();
  1539. $this->assertCount(1, $result, '1 row should be inserted');
  1540. $expected = [
  1541. [
  1542. 'id' => 4,
  1543. 'author_id' => null,
  1544. 'title' => 'mark',
  1545. 'body' => null,
  1546. 'published' => 'N',
  1547. ]
  1548. ];
  1549. $this->assertTable('articles', 1, $expected, ['id >= 4']);
  1550. }
  1551. /**
  1552. * Test inserting multiple rows with sparse data.
  1553. *
  1554. * @return void
  1555. */
  1556. public function testInsertMultipleRowsSparse() {
  1557. $query = new Query($this->connection);
  1558. $query->insert('articles', ['title', 'body'])
  1559. ->values([
  1560. 'body' => 'test insert'
  1561. ])
  1562. ->values([
  1563. 'title' => 'jose',
  1564. ]);
  1565. $result = $query->execute();
  1566. $this->assertCount(2, $result, '2 rows should be inserted');
  1567. $expected = [
  1568. [
  1569. 'id' => 4,
  1570. 'author_id' => null,
  1571. 'title' => null,
  1572. 'body' => 'test insert',
  1573. 'published' => 'N',
  1574. ],
  1575. [
  1576. 'id' => 5,
  1577. 'author_id' => null,
  1578. 'title' => 'jose',
  1579. 'body' => null,
  1580. 'published' => 'N',
  1581. ],
  1582. ];
  1583. $this->assertTable('articles', 2, $expected, ['id >=' => 4]);
  1584. }
  1585. /**
  1586. * Test that INSERT INTO ... SELECT works.
  1587. *
  1588. * @return void
  1589. */
  1590. public function testInsertFromSelect() {
  1591. $select = (new Query($this->connection))->select("name, 'some text', 99")
  1592. ->from('authors')
  1593. ->where(['id' => 1]);
  1594. $query = new Query($this->connection);
  1595. $query->insert(
  1596. 'articles',
  1597. ['title', 'body', 'author_id'],
  1598. ['title' => 'string', 'body' => 'string', 'author_id' => 'integer']
  1599. )
  1600. ->values($select);
  1601. $result = $query->sql();
  1602. $this->assertContains('INSERT INTO articles (title, body, author_id) SELECT', $result);
  1603. $this->assertContains("SELECT name, 'some text', 99 FROM authors", $result);
  1604. $result = $query->execute();
  1605. $this->assertCount(1, $result);
  1606. $result = (new Query($this->connection))->select('*')
  1607. ->from('articles')
  1608. ->where(['author_id' => 99])
  1609. ->execute();
  1610. $this->assertCount(1, $result);
  1611. $expected = [
  1612. 'id' => 4,
  1613. 'title' => 'mariano',
  1614. 'body' => 'some text',
  1615. 'author_id' => 99,
  1616. 'published' => 'N',
  1617. ];
  1618. $this->assertEquals($expected, $result->fetch('assoc'));
  1619. }
  1620. /**
  1621. * Test that an exception is raised when mixing query + array types.
  1622. *
  1623. * @expectedException Cake\Error\Exception
  1624. */
  1625. public function testInsertFailureMixingTypesArrayFirst() {
  1626. $query = new Query($this->connection);
  1627. $query->insert('articles', ['name'])
  1628. ->values(['name' => 'mark'])
  1629. ->values(new Query($this->connection));
  1630. }
  1631. /**
  1632. * Test that an exception is raised when mixing query + array types.
  1633. *
  1634. * @expectedException Cake\Error\Exception
  1635. */
  1636. public function testInsertFailureMixingTypesQueryFirst() {
  1637. $query = new Query($this->connection);
  1638. $query->insert('articles', ['name'])
  1639. ->values(new Query($this->connection))
  1640. ->values(['name' => 'mark']);
  1641. }
  1642. /**
  1643. * Tests that functions are correctly transformed and their parameters are bound
  1644. *
  1645. * @group FunctionExpression
  1646. * @return void
  1647. */
  1648. public function testSQLFunctions() {
  1649. $query = new Query($this->connection);
  1650. $result = $query->select(
  1651. function($q) {
  1652. return ['total' => $q->count('*')];
  1653. }
  1654. )
  1655. ->from('articles')
  1656. ->execute();
  1657. $expected = [['total' => 3]];
  1658. $this->assertEquals($expected, $result->fetchAll('assoc'));
  1659. $query = new Query($this->connection);
  1660. $result = $query->select(['c' => $query->concat(['title' => 'literal', ' is appended'])])
  1661. ->from('articles')
  1662. ->order(['c' => 'ASC'])
  1663. ->execute();
  1664. $expected = [
  1665. ['c' => 'First Article is appended'],
  1666. ['c' => 'Second Article is appended'],
  1667. ['c' => 'Third Article is appended']
  1668. ];
  1669. $this->assertEquals($expected, $result->fetchAll('assoc'));
  1670. $query = new Query($this->connection);
  1671. $result = $query
  1672. ->select(['d' => $query->dateDiff(['2012-01-05', '2012-01-02'])])
  1673. ->execute();
  1674. $this->assertEquals([['d' => '3.0']], $result->fetchAll('assoc'));
  1675. $query = new Query($this->connection);
  1676. $result = $query
  1677. ->select(['d' => $query->now('date')])
  1678. ->execute();
  1679. $this->assertEquals([['d' => date('Y-m-d')]], $result->fetchAll('assoc'));
  1680. $query = new Query($this->connection);
  1681. $result = $query
  1682. ->select(['d' => $query->now('time')])
  1683. ->execute();
  1684. $this->assertWithinMargin(
  1685. date('U'),
  1686. (new \DateTime($result->fetchAll('assoc')[0]['d']))->format('U'),
  1687. 1
  1688. );
  1689. $query = new Query($this->connection);
  1690. $result = $query
  1691. ->select(['d' => $query->now()])
  1692. ->execute();
  1693. $this->assertWithinMargin(
  1694. date('U'),
  1695. (new \DateTime($result->fetchAll('assoc')[0]['d']))->format('U'),
  1696. 1
  1697. );
  1698. }
  1699. /**
  1700. * Tests that default types are passed to functions accepting a $types param
  1701. *
  1702. * @return void
  1703. */
  1704. public function testDefaultTypes() {
  1705. $query = new Query($this->connection);
  1706. $this->assertEquals([], $query->defaultTypes());
  1707. $types = ['id' => 'integer', 'created' => 'datetime'];
  1708. $this->assertSame($query, $query->defaultTypes($types));
  1709. $this->assertSame($types, $query->defaultTypes());
  1710. $results = $query->select(['id', 'comment'])
  1711. ->from('comments')
  1712. ->where(['created >=' => new \DateTime('2007-03-18 10:55:00')])
  1713. ->execute();
  1714. $expected = [['id' => '6', 'comment' => 'Second Comment for Second Article']];
  1715. $this->assertEquals($expected, $results->fetchAll('assoc'));
  1716. // Now test default can be overridden
  1717. $types = ['created' => 'date'];
  1718. $results = $query
  1719. ->where(['created >=' => new \DateTime('2007-03-18 10:50:00')], $types, true)
  1720. ->execute();
  1721. $this->assertCount(6, $results, 'All 6 rows should match.');
  1722. }
  1723. /**
  1724. * Tests parameter binding
  1725. *
  1726. * @return void
  1727. */
  1728. public function testBind() {
  1729. $query = new Query($this->connection);
  1730. $results = $query->select(['id', 'comment'])
  1731. ->from('comments')
  1732. ->where(['created BETWEEN :foo AND :bar'])
  1733. ->bind(':foo', new \DateTime('2007-03-18 10:50:00'), 'datetime')
  1734. ->bind(':bar', new \DateTime('2007-03-18 10:52:00'), 'datetime')
  1735. ->execute();
  1736. $expected = [['id' => '4', 'comment' => 'Fourth Comment for First Article']];
  1737. $this->assertEquals($expected, $results->fetchAll('assoc'));
  1738. $query = new Query($this->connection);
  1739. $results = $query->select(['id', 'comment'])
  1740. ->from('comments')
  1741. ->where(['created BETWEEN :foo AND :bar'])
  1742. ->bind(':foo', '2007-03-18 10:50:00')
  1743. ->bind(':bar', '2007-03-18 10:52:00')
  1744. ->execute();
  1745. $this->assertEquals($expected, $results->fetchAll('assoc'));
  1746. }
  1747. /**
  1748. * Assertion for comparing a table's contents with what is in it.
  1749. *
  1750. * @param string $table
  1751. * @param integer $count
  1752. * @param array $rows
  1753. * @return void
  1754. */
  1755. public function assertTable($table, $count, $rows, $conditions = []) {
  1756. $result = (new Query($this->connection))->select('*')
  1757. ->from($table)
  1758. ->where($conditions)
  1759. ->execute();
  1760. $this->assertCount($count, $result, 'Row count is incorrect');
  1761. $this->assertEquals($rows, $result->fetchAll('assoc'));
  1762. }
  1763. }