/unit-tests/MvcModelQueryBuilderTest.php

https://gitlab.com/szlongshu/manaphp · PHP · 500 lines · 396 code · 73 blank · 31 comment · 4 complexity · 90ad615a9bf388ac5719a0d69b8dba0a MD5 · raw file

  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Mark
  5. * Date: 2015/12/27
  6. * Time: 20:13
  7. */
  8. defined('UNIT_TESTS_ROOT') || require __DIR__ . '/bootstrap.php';
  9. use Models\Address;
  10. use Models\City;
  11. use Models\Country;
  12. use Models\Payment;
  13. class MvcModelQueryBuilderTest extends TestCase
  14. {
  15. protected $di;
  16. /**
  17. * @var \ManaPHP\Mvc\Model\Manager
  18. */
  19. protected $modelsManager;
  20. public function setUp()
  21. {
  22. $this->di = new ManaPHP\Di();
  23. $this->di->set('modelsManager', function () {
  24. return new ManaPHP\Mvc\Model\Manager();
  25. });
  26. $this->di->set('modelsMetadata', function () {
  27. return new ManaPHP\Mvc\Model\MetaData\Memory();
  28. });
  29. $this->di->setShared('db', function () {
  30. $config = require __DIR__.'/config.database.php';
  31. $db = new ManaPHP\Db\Adapter\Mysql($config['mysql']);
  32. $db->attachEvent('db:beforeQuery', function ($event, ManaPHP\DbInterface $source) {
  33. var_dump($source->getSQL());
  34. var_dump($source->getEmulatedSQL());
  35. });
  36. return $db;
  37. });
  38. $this->modelsManager = $this->di->get('modelsManager');
  39. }
  40. public function test_distinct()
  41. {
  42. //select all implicitly
  43. $builder = $this->modelsManager->createBuilder()->columns('city_id')->addFrom(get_class(new Address()));
  44. $this->assertCount(603, $builder->getQuery()->execute());
  45. //select all explicitly
  46. $builder = $this->modelsManager->createBuilder()
  47. ->columns('city_id')
  48. ->addFrom(get_class(new Address()))
  49. ->distinct(false);
  50. $this->assertCount(603, $builder->getQuery()->execute());
  51. //select distinct
  52. $builder = $this->modelsManager->createBuilder()
  53. ->columns('city_id')
  54. ->addFrom(get_class(new Address()))
  55. ->distinct(true);
  56. $this->assertCount(599, $builder->getQuery()->execute());
  57. }
  58. public function test_columns()
  59. {
  60. //default select all columns
  61. $builder = $this->modelsManager->createBuilder()->addFrom(get_class(new Address()))->limit(2);
  62. $rows = $builder->getQuery()->execute();
  63. $this->assertCount(2, $rows);
  64. $this->assertCount(8, $rows[0]);
  65. //select all columns explicitly
  66. $builder = $this->modelsManager->createBuilder()->columns('*')->addFrom(get_class(new Address()))->limit(2);
  67. $rows = $builder->getQuery()->execute();
  68. $this->assertCount(2, $rows);
  69. $this->assertCount(8, $rows[0]);
  70. // select all columns explicitly and use table alias
  71. $builder = $this->modelsManager->createBuilder()
  72. ->columns('a.*, c.*')
  73. ->addFrom(get_class(new Address()), 'a')
  74. ->leftJoin(get_class(new City()), 'c.city_id =a.city_id', 'c')
  75. ->limit(2);
  76. $rows = $builder->getQuery()->execute();
  77. $this->assertCount(2, $rows);
  78. $this->assertCount(10, $rows[0]);
  79. //string format columns
  80. $builder = $this->modelsManager->createBuilder()
  81. ->columns('a.address_id, a.address, a.phone')
  82. ->addFrom(get_class(new Address()), 'a')
  83. ->limit(2);
  84. $rows = $builder->getQuery()->execute();
  85. $this->assertCount(2, $rows);
  86. $this->assertCount(3, $rows[0]);
  87. //array format columns
  88. $builder = $this->modelsManager->createBuilder()
  89. ->columns(['a.address_id', 'a.address', 'a.phone'])
  90. ->addFrom(get_class(new Address()), 'a')
  91. ->limit(2);
  92. $rows = $builder->getQuery()->execute();
  93. $this->assertCount(2, $rows);
  94. $this->assertCount(3, $rows[0]);
  95. //dense multi space to only one for columns
  96. $builder = $this->modelsManager->createBuilder()
  97. ->columns('a.address_id,
  98. a.address,
  99. c.city')
  100. ->addFrom(get_class(new Address()), 'a')
  101. ->leftJoin(get_class(new City()), 'c.city_id =a.city_id', 'c')
  102. ->limit(2)
  103. ->orderBy('a.address_id');
  104. $rows = $builder->getQuery()->execute();
  105. $this->assertCount(2, $rows);
  106. $this->assertCount(3, $rows[0]);
  107. $builder = $this->modelsManager->createBuilder()
  108. ->columns('count(address_id) as address_count')
  109. ->addFrom(get_class(new Address()));
  110. $rows = $builder->getQuery()->execute();
  111. $this->assertCount(1, $rows);
  112. $this->assertCount(1, $rows[0]);
  113. }
  114. public function test_from()
  115. {
  116. $builder = $this->modelsManager->createBuilder()
  117. ->columns('address_id,address,phone')
  118. ->from(get_class(new Address()))
  119. ->limit(2);
  120. $rows = $builder->getQuery()->execute();
  121. $this->assertCount(2, $rows);
  122. $this->assertCount(3, $rows[0]);
  123. }
  124. public function test_addFrom()
  125. {
  126. //one model without alias
  127. $builder = $this->modelsManager->createBuilder()
  128. ->columns('address_id,address,phone')
  129. ->addFrom(get_class(new Address()))
  130. ->limit(2);
  131. $rows = $builder->getQuery()->execute();
  132. $this->assertCount(2, $rows);
  133. $this->assertCount(3, $rows[0]);
  134. //one model with alias
  135. $builder = $this->modelsManager->createBuilder()
  136. ->columns('a.address_id,a.address,a.phone')
  137. ->addFrom(get_class(new Address()), 'a')
  138. ->limit(2);
  139. $rows = $builder->getQuery()->execute();
  140. $this->assertCount(2, $rows);
  141. $this->assertCount(3, $rows[0]);
  142. //multi-models with alias
  143. $builder = $this->modelsManager->createBuilder()
  144. ->columns('a.*, c.*')
  145. ->addFrom(get_class(new Address()), 'a')
  146. ->addFrom(get_class(new City()), 'c')
  147. ->limit(2);
  148. $rows = $builder->getQuery()->execute();
  149. $this->assertCount(2, $rows);
  150. $this->assertCount(10, $rows[0]);
  151. }
  152. public function test_join()
  153. {
  154. //with model
  155. $builder = $this->modelsManager->createBuilder()
  156. ->columns('count(address_id) as address_count')
  157. ->addFrom(get_class(new Address()))
  158. ->join(get_class(new City()));
  159. $rows = $builder->getQuery()->execute();
  160. $this->assertCount(1, $rows);
  161. $this->assertEquals(361800, $rows[0]['address_count']);
  162. //with model,conditions
  163. $builder = $this->modelsManager->createBuilder()
  164. ->columns('count(address_id) as address_count')
  165. ->addFrom(get_class(new Address()), 'a')
  166. ->join(get_class(new City()), 'city.city_id =a.city_id');
  167. $rows = $builder->getQuery()->execute();
  168. $this->assertCount(1, $rows);
  169. $this->assertEquals(603, $rows[0]['address_count']);
  170. //with model,conditions,alias
  171. $builder = $this->modelsManager->createBuilder()
  172. ->columns('count(address_id) as address_count')
  173. ->addFrom(get_class(new Address()), 'a')
  174. ->join(get_class(new City()), 'c.city_id =a.city_id', 'c');
  175. $rows = $builder->getQuery()->execute();
  176. $this->assertCount(1, $rows);
  177. $this->assertEquals(603, $rows[0]['address_count']);
  178. //with model,conditions,alias,join
  179. $builder = $this->modelsManager->createBuilder()
  180. ->columns('a.address_id, a.address, a.city_id, c.city')
  181. ->addFrom(get_class(new Address()), 'a')
  182. ->join(get_class(new City()), 'c.city_id =a.city_id', 'c', 'LEFT');
  183. $rows = $builder->getQuery()->execute();
  184. $this->assertCount(603, $rows);
  185. }
  186. public function test_innerJoin()
  187. {
  188. $countCity = City::count();
  189. $this->assertEquals(600, $countCity);
  190. $countCountry = Country::count();
  191. $this->assertEquals(109, $countCountry);
  192. $builder = $this->modelsManager->createBuilder()
  193. ->columns('c1.*,c2.*')
  194. ->addFrom(get_class(new City()), 'c1')
  195. ->innerJoin(get_class(new Country()), 'c1.city_id=c2.country_id', 'c2');
  196. $this->assertCount($countCountry, $builder->getQuery()->execute());
  197. }
  198. public function test_leftJoin()
  199. {
  200. $countCity = City::count();
  201. $this->assertEquals(600, $countCity);
  202. $countCountry = Country::count();
  203. $this->assertEquals(109, $countCountry);
  204. $builder = $this->modelsManager->createBuilder()
  205. ->columns('c1.*,c2.*')
  206. ->addFrom(get_class(new City()), 'c1')
  207. ->leftJoin(get_class(new Country()), 'c1.city_id=c2.country_id', 'c2');
  208. $this->assertCount($countCity, $builder->getQuery()->execute());
  209. }
  210. public function test_rightJoin()
  211. {
  212. $countCity = City::count();
  213. $this->assertEquals(600, $countCity);
  214. $countCountry = Country::count();
  215. $this->assertEquals(109, $countCountry);
  216. $builder = $this->modelsManager->createBuilder()
  217. ->columns('c1.*,c2.*')
  218. ->addFrom(get_class(new City()), 'c1')
  219. ->rightJoin(get_class(new Country()), 'c1.city_id=c2.country_id', 'c2');
  220. $this->assertCount($countCountry, $builder->getQuery()->execute());
  221. }
  222. public function test_where()
  223. {
  224. $builder = $this->modelsManager->createBuilder()->where('address_id <=100')->addFrom(get_class(new Address()));
  225. $this->assertCount(100, $builder->getQuery()->execute());
  226. $builder = $this->modelsManager->createBuilder()
  227. ->where('address_id <=:max_address_id', ['max_address_id' => 100])
  228. ->addFrom(get_class(new Address()));
  229. $this->assertCount(100, $builder->getQuery()->execute());
  230. $builder = $this->modelsManager->createBuilder()
  231. ->where('address_id >=:min_address_id AND address_id <=:max_address_id',
  232. ['min_address_id' => 51, 'max_address_id' => 100])
  233. ->addFrom(get_class(new Address()));
  234. $this->assertCount(50, $builder->getQuery()->execute());
  235. }
  236. public function test_andWhere()
  237. {
  238. $builder = $this->modelsManager->createBuilder()
  239. ->andWhere('address_id <=100')
  240. ->addFrom(get_class(new Address()));
  241. $this->assertCount(100, $builder->getQuery()->execute());
  242. $builder = $this->modelsManager->createBuilder()
  243. ->andWhere('address_id <=:max_address_id', ['max_address_id' => 100])
  244. ->addFrom(get_class(new Address()));
  245. $this->assertCount(100, $builder->getQuery()->execute());
  246. $builder = $this->modelsManager->createBuilder()
  247. ->andWhere('address_id >=:min_address_id', ['min_address_id' => 51])
  248. ->andWhere('address_id <=:max_address_id', ['max_address_id' => 100])
  249. ->addFrom(get_class(new Address()));
  250. $this->assertCount(50, $builder->getQuery()->execute());
  251. }
  252. public function test_betweenWhere()
  253. {
  254. $builder = $this->modelsManager->createBuilder()
  255. ->betweenWhere('address_id', 51, 100)
  256. ->addFrom(get_class(new Address()));
  257. $this->assertCount(50, $builder->getQuery()->execute());
  258. $builder = $this->modelsManager->createBuilder()
  259. ->betweenWhere('address_id', 51, 100)
  260. ->betweenWhere('address_id', 61, 70)
  261. ->addFrom(get_class(new Address()));
  262. $this->assertCount(10, $builder->getQuery()->execute());
  263. }
  264. public function test_notBetweenWhere()
  265. {
  266. $builder = $this->modelsManager->createBuilder()
  267. ->notBetweenWhere('address_id', 51, 1000000)
  268. ->addFrom(get_class(new Address()));
  269. $this->assertCount(50, $builder->getQuery()->execute());
  270. $builder = $this->modelsManager->createBuilder()
  271. ->notBetweenWhere('address_id', 51, 1000000)
  272. ->notBetweenWhere('address_id', 71, 7000000)
  273. ->addFrom(get_class(new Address()));
  274. $this->assertCount(50, $builder->getQuery()->execute());
  275. }
  276. public function test_inWhere()
  277. {
  278. $builder = $this->modelsManager->createBuilder()->inWhere('address_id', [])->addFrom(get_class(new Address()));
  279. $this->assertCount(0, $builder->getQuery()->execute());
  280. $builder = $this->modelsManager->createBuilder()->inWhere('address_id', [1])->addFrom(get_class(new Address()));
  281. $this->assertCount(1, $builder->getQuery()->execute());
  282. $builder = $this->modelsManager->createBuilder()
  283. ->inWhere('address_id', [1, 2, 3, 4, 5])
  284. ->addFrom(get_class(new Address()));
  285. $this->assertCount(5, $builder->getQuery()->execute());
  286. $builder = $this->modelsManager->createBuilder()
  287. ->inWhere('address_id', [-3, -2, -1, 0, 1, 2])
  288. ->addFrom(get_class(new Address()));
  289. $this->assertCount(2, $builder->getQuery()->execute());
  290. }
  291. public function test_orderBy()
  292. {
  293. $builder = $this->modelsManager->createBuilder()
  294. ->columns('address_id')
  295. ->addFrom(get_class(new Address()))
  296. ->where('address_id <=:max_address_id', ['max_address_id' => 10])
  297. ->orderBy('address_id');
  298. $rows = $builder->getQuery()->execute();
  299. $this->assertCount(10, $builder->getQuery()->execute());
  300. /** @noinspection ForeachInvariantsInspection */
  301. for ($i = 0; $i < count($rows) - 1; $i++) {
  302. $this->assertTrue($rows[$i]['address_id'] < $rows[$i + 1]['address_id']);
  303. }
  304. $builder = $this->modelsManager->createBuilder()
  305. ->columns('address_id')
  306. ->addFrom(get_class(new Address()))
  307. ->where('address_id <=:max_address_id', ['max_address_id' => 10])
  308. ->orderBy('address_id ASC');
  309. $rows = $builder->getQuery()->execute();
  310. $this->assertCount(10, $builder->getQuery()->execute());
  311. /** @noinspection ForeachInvariantsInspection */
  312. for ($i = 0; $i < count($rows) - 1; $i++) {
  313. $this->assertTrue($rows[$i]['address_id'] < $rows[$i + 1]['address_id']);
  314. }
  315. $builder = $this->modelsManager->createBuilder()
  316. ->columns('address_id')
  317. ->addFrom(get_class(new Address()))
  318. ->where('address_id <=:max_address_id', ['max_address_id' => 10])
  319. ->orderBy('address_id DESC');
  320. $rows = $builder->getQuery()->execute();
  321. $this->assertCount(10, $builder->getQuery()->execute());
  322. /** @noinspection ForeachInvariantsInspection */
  323. for ($i = 0; $i < count($rows) - 1; $i++) {
  324. $this->assertTrue($rows[$i]['address_id'] > $rows[$i + 1]['address_id']);
  325. }
  326. }
  327. public function test_having()
  328. {
  329. $builder = $this->modelsManager->createBuilder()
  330. ->columns('COUNT(city_id) as count_city, country_id')
  331. ->addFrom(get_class(new City()))
  332. ->groupBy('country_id')
  333. ->having('COUNT(city_id) >1');
  334. $rows = $builder->getQuery()->execute();
  335. $this->assertCount(67, $rows);
  336. foreach ($rows as $row) {
  337. $this->assertTrue($row['count_city'] > 1);
  338. }
  339. $builder = $this->modelsManager->createBuilder()
  340. ->columns('COUNT(city_id) as count_city, country_id')
  341. ->addFrom(get_class(new City()))
  342. ->groupBy('country_id')
  343. ->having('COUNT(city_id) >1')
  344. ->having('COUNT(city_id) <7');
  345. $rows = $builder->getQuery()->execute();
  346. $this->assertCount(46, $rows);
  347. foreach ($rows as $row) {
  348. $this->assertTrue($row['count_city'] > 1);
  349. $this->assertTrue($row['count_city'] < 7);
  350. }
  351. $builder = $this->modelsManager->createBuilder()
  352. ->columns('COUNT(city_id) as count_city, country_id')
  353. ->addFrom(get_class(new City()))
  354. ->groupBy('country_id')
  355. ->having('COUNT(city_id) >:min_count', ['min_count' => 1])
  356. ->having('COUNT(city_id) <:max_count', ['max_count' => 7]);
  357. $rows = $builder->getQuery()->execute();
  358. $this->assertCount(46, $rows);
  359. }
  360. public function test_limit()
  361. {
  362. //limit without offset
  363. $builder = $this->modelsManager->createBuilder()->columns('city_id')->addFrom(get_class(new City()))->limit(1);
  364. $this->assertCount(1, $builder->getQuery()->execute());
  365. //limit with offset
  366. $builder = $this->modelsManager->createBuilder()
  367. ->columns('city_id')
  368. ->addFrom(get_class(new City()))
  369. ->orderBy('city_id')
  370. ->limit(10, 20);
  371. $rows = $builder->getQuery()->execute();
  372. $this->assertCount(10, $rows);
  373. $this->assertEquals(21, $rows[0]['city_id']);
  374. $this->assertEquals(30, $rows[9]['city_id']);
  375. //there is no error during limiting equal to 0
  376. $builder = $this->modelsManager->createBuilder()->columns('city_id')->addFrom(get_class(new City()))->limit(0);
  377. $this->assertCount(0, $builder->getQuery()->execute());
  378. }
  379. public function test_offset()
  380. {
  381. $builder = $this->modelsManager->createBuilder()
  382. ->columns('city_id')
  383. ->addFrom(get_class(new City()))
  384. ->andWhere('city_id <:city_id', ['city_id' => 10])
  385. ->limit(2)
  386. ->offset(5);
  387. $rows = $builder->getQuery()->execute();
  388. $this->assertCount(2, $rows);
  389. $this->assertEquals(6, $rows[0]['city_id']);
  390. }
  391. public function test_groupBy()
  392. {
  393. $builder = $this->modelsManager->createBuilder()
  394. ->columns('COUNT(city_id) as count_city, country_id')
  395. ->addFrom(get_class(new City()))
  396. ->groupBy('country_id');
  397. $rows = $builder->getQuery()->execute();
  398. $this->assertCount(109, $rows);
  399. $builder = $this->modelsManager->createBuilder()
  400. ->columns('COUNT(payment_id) AS payment_times, customer_id, amount')
  401. ->addFrom(get_class(new Payment()))
  402. ->groupBy('customer_id,amount');
  403. $rows = $builder->getQuery()->execute();
  404. $this->assertCount(4812, $rows);
  405. }
  406. public function test_notInWhere()
  407. {
  408. $rowAddress = Address::count();
  409. $this->assertEquals(603, $rowAddress);
  410. $builder = $this->modelsManager->createBuilder()
  411. ->notInWhere('address_id', [])
  412. ->addFrom(get_class(new Address()));
  413. $this->assertCount(603, $builder->getQuery()->execute());
  414. $builder = $this->modelsManager->createBuilder()
  415. ->notInWhere('address_id', [1])
  416. ->addFrom(get_class(new Address()));
  417. $this->assertCount(602, $builder->getQuery()->execute());
  418. $builder = $this->modelsManager->createBuilder()
  419. ->notInWhere('address_id', [1, 2, 3])
  420. ->addFrom(get_class(new Address()));
  421. $this->assertCount(600, $builder->getQuery()->execute());
  422. $builder = $this->modelsManager->createBuilder()
  423. ->notInWhere('address_id', [-3, -2, -1, 0, 1, 2])
  424. ->addFrom(get_class(new Address()));
  425. $this->assertCount(601, $builder->getQuery()->execute());
  426. }
  427. }