QueryRunTest.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. <?php
  2. namespace yiiunit\extensions\mongodb;
  3. use MongoDB\BSON\ObjectID;
  4. use yii\mongodb\Query;
  5. class QueryRunTest extends TestCase
  6. {
  7. protected function setUp()
  8. {
  9. parent::setUp();
  10. $this->setUpTestRows();
  11. }
  12. protected function tearDown()
  13. {
  14. $this->dropCollection('customer');
  15. parent::tearDown();
  16. }
  17. /**
  18. * Sets up test rows.
  19. */
  20. protected function setUpTestRows()
  21. {
  22. $collection = $this->getConnection()->getCollection('customer');
  23. $rows = [];
  24. for ($i = 1; $i <= 10; $i++) {
  25. $rows[] = [
  26. 'name' => 'name' . $i,
  27. 'status' => $i,
  28. 'address' => 'address' . $i,
  29. 'group' => ($i % 2 === 0) ? 'even' : 'odd',
  30. 'avatar' => [
  31. 'width' => 50 + $i,
  32. 'height' => 100 + $i,
  33. 'url' => 'http://some.url/' . $i,
  34. ],
  35. ];
  36. }
  37. $collection->batchInsert($rows);
  38. }
  39. // Tests :
  40. public function testAll()
  41. {
  42. $connection = $this->getConnection();
  43. $query = new Query();
  44. $rows = $query->from('customer')->all($connection);
  45. $this->assertEquals(10, count($rows));
  46. }
  47. public function testDirectMatch()
  48. {
  49. $connection = $this->getConnection();
  50. $query = new Query();
  51. $rows = $query->from('customer')
  52. ->where(['name' => 'name1'])
  53. ->all($connection);
  54. $this->assertEquals(1, count($rows));
  55. $this->assertEquals('name1', $rows[0]['name']);
  56. }
  57. public function testIndexBy()
  58. {
  59. $connection = $this->getConnection();
  60. $query = new Query();
  61. $rows = $query->from('customer')
  62. ->indexBy('name')
  63. ->all($connection);
  64. $this->assertEquals(10, count($rows));
  65. $this->assertNotEmpty($rows['name1']);
  66. }
  67. public function testInCondition()
  68. {
  69. $connection = $this->getConnection();
  70. $query = new Query();
  71. $rows = $query->from('customer')
  72. ->where([
  73. 'name' => ['name1', 'name5']
  74. ])
  75. ->all($connection);
  76. $this->assertEquals(2, count($rows));
  77. $this->assertEquals('name1', $rows[0]['name']);
  78. $this->assertEquals('name5', $rows[1]['name']);
  79. }
  80. public function testNotInCondition()
  81. {
  82. $connection = $this->getConnection();
  83. $query = new Query();
  84. $rows = $query->from('customer')
  85. ->where(['not in', 'name', ['name1', 'name5']])
  86. ->all($connection);
  87. $this->assertEquals(8, count($rows));
  88. $query = new Query();
  89. $rows = $query->from('customer')
  90. ->where(['not in', 'name', ['name1']])
  91. ->all($connection);
  92. $this->assertEquals(9, count($rows));
  93. }
  94. /**
  95. * @depends testInCondition
  96. */
  97. public function testCompositeInCondition()
  98. {
  99. $connection = $this->getConnection();
  100. $query = new Query();
  101. $rows = $query->from('customer')
  102. ->where([
  103. 'in',
  104. ['status', 'name'],
  105. [
  106. ['status' => 1, 'name' => 'name1'],
  107. ['status' => 3, 'name' => 'name3'],
  108. ['status' => 5, 'name' => 'name7'],
  109. ]
  110. ])
  111. ->all($connection);
  112. $this->assertEquals(2, count($rows));
  113. $this->assertEquals('name1', $rows[0]['name']);
  114. $this->assertEquals('name3', $rows[1]['name']);
  115. }
  116. public function testOrCondition()
  117. {
  118. $connection = $this->getConnection();
  119. $query = new Query();
  120. $rows = $query->from('customer')
  121. ->where(['name' => 'name1'])
  122. ->orWhere(['address' => 'address5'])
  123. ->all($connection);
  124. $this->assertEquals(2, count($rows));
  125. $this->assertEquals('name1', $rows[0]['name']);
  126. $this->assertEquals('address5', $rows[1]['address']);
  127. }
  128. public function testCombinedInAndCondition()
  129. {
  130. $connection = $this->getConnection();
  131. $query = new Query();
  132. $rows = $query->from('customer')
  133. ->where([
  134. 'name' => ['name1', 'name5']
  135. ])
  136. ->andWhere(['name' => 'name1'])
  137. ->all($connection);
  138. $this->assertEquals(1, count($rows));
  139. $this->assertEquals('name1', $rows[0]['name']);
  140. }
  141. public function testCombinedInLikeAndCondition()
  142. {
  143. $connection = $this->getConnection();
  144. $query = new Query();
  145. $rows = $query->from('customer')
  146. ->where([
  147. 'name' => ['name1', 'name5', 'name10']
  148. ])
  149. ->andWhere(['LIKE', 'name', 'me1'])
  150. ->andWhere(['name' => 'name10'])
  151. ->all($connection);
  152. $this->assertEquals(1, count($rows));
  153. $this->assertEquals('name10', $rows[0]['name']);
  154. }
  155. public function testNestedCombinedInAndCondition()
  156. {
  157. $connection = $this->getConnection();
  158. $query = new Query();
  159. $rows = $query->from('customer')
  160. ->where([
  161. 'and',
  162. ['name' => ['name1', 'name2', 'name3']],
  163. ['name' => 'name1']
  164. ])
  165. ->orWhere([
  166. 'and',
  167. ['name' => ['name4', 'name5', 'name6']],
  168. ['name' => 'name6']
  169. ])
  170. ->all($connection);
  171. $this->assertEquals(2, count($rows));
  172. $this->assertEquals('name1', $rows[0]['name']);
  173. $this->assertEquals('name6', $rows[1]['name']);
  174. }
  175. public function testOrder()
  176. {
  177. $connection = $this->getConnection();
  178. $query = new Query();
  179. $rows = $query->from('customer')
  180. ->orderBy(['name' => SORT_DESC])
  181. ->all($connection);
  182. $this->assertEquals('name9', $rows[0]['name']);
  183. $query = new Query();
  184. $rows = $query->from('customer')
  185. ->orderBy(['avatar.height' => SORT_DESC])
  186. ->all($connection);
  187. $this->assertEquals('name10', $rows[0]['name']);
  188. }
  189. public function testMatchPlainId()
  190. {
  191. $connection = $this->getConnection();
  192. $query = new Query();
  193. $row = $query->from('customer')->one($connection);
  194. $query = new Query();
  195. $rows = $query->from('customer')
  196. ->where(['_id' => $row['_id']->__toString()])
  197. ->all($connection);
  198. $this->assertEquals(1, count($rows));
  199. }
  200. public function testRegex()
  201. {
  202. $connection = $this->getConnection();
  203. $query = new Query();
  204. $rows = $query->from('customer')
  205. ->where(['REGEX', 'name', '/me1/'])
  206. ->all($connection);
  207. $this->assertEquals(2, count($rows));
  208. $this->assertEquals('name1', $rows[0]['name']);
  209. $this->assertEquals('name10', $rows[1]['name']);
  210. }
  211. public function testLike()
  212. {
  213. $connection = $this->getConnection();
  214. $query = new Query();
  215. $rows = $query->from('customer')
  216. ->where(['LIKE', 'name', 'me1'])
  217. ->all($connection);
  218. $this->assertEquals(2, count($rows));
  219. $this->assertEquals('name1', $rows[0]['name']);
  220. $this->assertEquals('name10', $rows[1]['name']);
  221. $query = new Query();
  222. $rowsUppercase = $query->from('customer')
  223. ->where(['LIKE', 'name', 'ME1'])
  224. ->all($connection);
  225. $this->assertEquals($rows, $rowsUppercase);
  226. }
  227. public function testCompare()
  228. {
  229. $connection = $this->getConnection();
  230. $query = new Query();
  231. $rows = $query->from('customer')
  232. ->where(['$gt', 'status', 8])
  233. ->all($connection);
  234. $this->assertEquals(2, count($rows));
  235. $query = new Query();
  236. $rows = $query->from('customer')
  237. ->where(['>', 'status', 8])
  238. ->all($connection);
  239. $this->assertEquals(2, count($rows));
  240. $query = new Query();
  241. $rows = $query->from('customer')
  242. ->where(['<=', 'status', 3])
  243. ->all($connection);
  244. $this->assertEquals(3, count($rows));
  245. }
  246. public function testNot()
  247. {
  248. $connection = $this->getConnection();
  249. $query = new Query();
  250. $rows = $query->from('customer')
  251. ->where(['not', 'status', ['$gte' => 10]])
  252. ->all($connection);
  253. $this->assertEquals(9, count($rows));
  254. $query = new Query();
  255. $rows = $query->from('customer')
  256. ->where(['not', 'name', 'name1'])
  257. ->all($connection);
  258. $this->assertEquals(9, count($rows));
  259. $query = new Query();
  260. $rows = $query->from('customer')
  261. ->where(['not', 'name', null])
  262. ->all($connection);
  263. $this->assertEquals(10, count($rows));
  264. }
  265. public function testExists()
  266. {
  267. $connection = $this->getConnection();
  268. $query = new Query();
  269. $exists = $query->from('customer')
  270. ->where(['name' => 'name1'])
  271. ->exists($connection);
  272. $this->assertTrue($exists);
  273. $query = new Query();
  274. $exists = $query->from('customer')
  275. ->where(['name' => 'un-existing-name'])
  276. ->exists($connection);
  277. $this->assertFalse($exists);
  278. }
  279. public function testModify()
  280. {
  281. $connection = $this->getConnection();
  282. $query = new Query();
  283. $searchName = 'name5';
  284. $newName = 'new name';
  285. $row = $query->from('customer')
  286. ->where(['name' => $searchName])
  287. ->modify(['$set' => ['name' => $newName]], ['new' => false], $connection);
  288. $this->assertEquals($searchName, $row['name']);
  289. $searchName = 'name7';
  290. $newName = 'new name';
  291. $row = $query->from('customer')
  292. ->where(['name' => $searchName])
  293. ->modify(['$set' => ['name' => $newName]], ['new' => true], $connection);
  294. $this->assertEquals($newName, $row['name']);
  295. $row = $query->from('customer')
  296. ->where(['name' => 'not existing name'])
  297. ->modify(['$set' => ['name' => 'new name']], ['new' => false], $connection);
  298. $this->assertNull($row);
  299. }
  300. /**
  301. * @see https://github.com/yiisoft/yii2/issues/4879
  302. * @see https://github.com/yiisoft/yii2-mongodb/issues/101
  303. *
  304. * @depends testInCondition
  305. */
  306. public function testInConditionIgnoreKeys()
  307. {
  308. $connection = $this->getConnection();
  309. $query = new Query();
  310. $rows = $query->from('customer')
  311. /*->where([
  312. 'name' => [
  313. 0 => 'name1',
  314. 15 => 'name5'
  315. ]
  316. ])*/
  317. ->where(['in', 'name', [
  318. 10 => 'name1',
  319. 15 => 'name5'
  320. ]])
  321. ->all($connection);
  322. $this->assertEquals(2, count($rows));
  323. $this->assertEquals('name1', $rows[0]['name']);
  324. $this->assertEquals('name5', $rows[1]['name']);
  325. // @see https://github.com/yiisoft/yii2-mongodb/issues/101
  326. $query = new Query();
  327. $rows = $query->from('customer')
  328. ->where(['_id' => [
  329. 10 => $rows[0]['_id'],
  330. 15 => $rows[1]['_id']
  331. ]])
  332. ->all($connection);
  333. $this->assertEquals(2, count($rows));
  334. }
  335. /**
  336. * @see https://github.com/yiisoft/yii2/issues/7010
  337. */
  338. public function testSelect()
  339. {
  340. $connection = $this->getConnection();
  341. $query = new Query();
  342. $rows = $query->from('customer')
  343. ->select(['name' => true, '_id' => false])
  344. ->limit(1)
  345. ->all($connection);
  346. $row = array_pop($rows);
  347. $this->assertArrayHasKey('name', $row);
  348. $this->assertArrayNotHasKey('address', $row);
  349. $this->assertArrayNotHasKey('_id', $row);
  350. }
  351. public function testScalar()
  352. {
  353. $connection = $this->getConnection();
  354. $result = (new Query())
  355. ->select(['name' => true, '_id' => false])
  356. ->from('customer')
  357. ->orderBy(['name' => SORT_ASC])
  358. ->limit(1)
  359. ->scalar($connection);
  360. $this->assertSame('name1', $result);
  361. $result = (new Query())
  362. ->select(['name' => true, '_id' => false])
  363. ->from('customer')
  364. ->andWhere(['status' => -1])
  365. ->scalar($connection);
  366. $this->assertSame(false, $result);
  367. $result = (new Query())
  368. ->select(['name'])
  369. ->from('customer')
  370. ->orderBy(['name' => SORT_ASC])
  371. ->limit(1)
  372. ->scalar($connection);
  373. $this->assertSame('name1', $result);
  374. $result = (new Query())
  375. ->select(['_id'])
  376. ->from('customer')
  377. ->limit(1)
  378. ->scalar($connection);
  379. $this->assertTrue($result instanceof ObjectID);
  380. }
  381. public function testColumn()
  382. {
  383. $connection = $this->getConnection();
  384. $result = (new Query())->from('customer')
  385. ->select(['name' => true, '_id' => false])
  386. ->orderBy(['name' => SORT_ASC])
  387. ->limit(2)
  388. ->column($connection);
  389. $this->assertEquals(['name1', 'name10'], $result);
  390. $result = (new Query())->from('customer')
  391. ->select(['name' => true, '_id' => false])
  392. ->andWhere(['status' => -1])
  393. ->orderBy(['name' => SORT_ASC])
  394. ->limit(2)
  395. ->column($connection);
  396. $this->assertEquals([], $result);
  397. $result = (new Query())->from('customer')
  398. ->select(['name'])
  399. ->orderBy(['name' => SORT_ASC])
  400. ->limit(2)
  401. ->column($connection);
  402. $this->assertEquals(['name1', 'name10'], $result);
  403. $result = (new Query())->from('customer')
  404. ->select(['_id'])
  405. ->orderBy(['name' => SORT_ASC])
  406. ->limit(2)
  407. ->column($connection);
  408. $this->assertTrue($result[0] instanceof ObjectID);
  409. $this->assertTrue($result[1] instanceof ObjectID);
  410. }
  411. /**
  412. * @depends testColumn
  413. */
  414. public function testColumnIndexBy()
  415. {
  416. $connection = $this->getConnection();
  417. $result = (new Query())->from('customer')
  418. ->select(['name'])
  419. ->orderBy(['name' => SORT_ASC])
  420. ->limit(2)
  421. ->indexBy('status')
  422. ->column($connection);
  423. $this->assertEquals([1 => 'name1', 10 => 'name10'], $result);
  424. $result = (new Query())->from('customer')
  425. ->select(['name', 'status'])
  426. ->orderBy(['name' => SORT_ASC])
  427. ->limit(2)
  428. ->indexBy(function ($row) {
  429. return $row['status'] * 2;
  430. })
  431. ->column($connection);
  432. $this->assertEquals([2 => 'name1', 20 => 'name10'], $result);
  433. $result = (new Query())->from('customer')
  434. ->select(['name'])
  435. ->orderBy(['name' => SORT_ASC])
  436. ->limit(2)
  437. ->indexBy('name')
  438. ->column($connection);
  439. $this->assertEquals(['name1' => 'name1', 'name10' => 'name10'], $result);
  440. }
  441. public function testEmulateExecution()
  442. {
  443. $query = new Query();
  444. if (!$query->hasMethod('emulateExecution')) {
  445. $this->markTestSkipped('"yii2" version 2.0.11 or higher required');
  446. }
  447. $db = $this->getConnection();
  448. $this->assertGreaterThan(0, $query->from('customer')->count('*', $db));
  449. $rows = (new Query())
  450. ->from('customer')
  451. ->emulateExecution()
  452. ->all($db);
  453. $this->assertSame([], $rows);
  454. $row = (new Query())
  455. ->from('customer')
  456. ->emulateExecution()
  457. ->one($db);
  458. $this->assertSame(false, $row);
  459. $exists = (new Query())
  460. ->from('customer')
  461. ->emulateExecution()
  462. ->exists($db);
  463. $this->assertSame(false, $exists);
  464. $count = (new Query())
  465. ->from('customer')
  466. ->emulateExecution()
  467. ->count('*', $db);
  468. $this->assertSame(0, $count);
  469. $sum = (new Query())
  470. ->from('customer')
  471. ->emulateExecution()
  472. ->sum('id', $db);
  473. $this->assertSame(0, $sum);
  474. $sum = (new Query())
  475. ->from('customer')
  476. ->emulateExecution()
  477. ->average('id', $db);
  478. $this->assertSame(0, $sum);
  479. $max = (new Query())
  480. ->from('customer')
  481. ->emulateExecution()
  482. ->max('id', $db);
  483. $this->assertSame(null, $max);
  484. $min = (new Query())
  485. ->from('customer')
  486. ->emulateExecution()
  487. ->min('id', $db);
  488. $this->assertSame(null, $min);
  489. $scalar = (new Query())
  490. ->select(['id'])
  491. ->from('customer')
  492. ->emulateExecution()
  493. ->scalar($db);
  494. $this->assertSame(null, $scalar);
  495. $column = (new Query())
  496. ->select(['id'])
  497. ->from('customer')
  498. ->emulateExecution()
  499. ->column($db);
  500. $this->assertSame([], $column);
  501. $row = (new Query())
  502. ->select(['id'])
  503. ->from('customer')
  504. ->emulateExecution()
  505. ->modify(['name' => 'new name'], [], $db);
  506. $this->assertSame(null, $row);
  507. $values = (new Query())
  508. ->select(['id'])
  509. ->from('customer')
  510. ->emulateExecution()
  511. ->distinct('name', $db);
  512. $this->assertSame([], $values);
  513. }
  514. /**
  515. * @depends testAll
  516. *
  517. * @see https://github.com/yiisoft/yii2-mongodb/issues/205
  518. */
  519. public function testOffsetLimit()
  520. {
  521. $db = $this->getConnection();
  522. $rows = (new Query())
  523. ->from('customer')
  524. ->limit(2)
  525. ->all($db);
  526. $this->assertCount(2, $rows);
  527. $rows = (new Query())
  528. ->from('customer')
  529. ->limit(-1)
  530. ->all($db);
  531. $this->assertCount(10, $rows);
  532. $rows = (new Query())
  533. ->from('customer')
  534. ->orderBy(['name' => SORT_ASC])
  535. ->offset(2)
  536. ->limit(1)
  537. ->all($db);
  538. $this->assertCount(1, $rows);
  539. $this->assertEquals('name2', $rows[0]['name']);
  540. $rows = (new Query())
  541. ->from('customer')
  542. ->orderBy(['name' => SORT_ASC])
  543. ->offset(-1)
  544. ->limit(1)
  545. ->all($db);
  546. $this->assertCount(1, $rows);
  547. $this->assertEquals('name1', $rows[0]['name']);
  548. }
  549. public function testDistinct()
  550. {
  551. $db = $this->getConnection();
  552. $rows = (new Query())
  553. ->from('customer')
  554. ->distinct('group', $db);
  555. $this->assertSame(['odd', 'even'], $rows);
  556. }
  557. public function testAggregationShortcuts()
  558. {
  559. $db = $this->getConnection();
  560. $max = (new Query())
  561. ->from('customer')
  562. ->where(['group' => 'odd'])
  563. ->count('*', $db);
  564. $this->assertSame(5, $max);
  565. $max = (new Query())
  566. ->from('customer')
  567. ->where(['group' => 'even'])
  568. ->max('status', $db);
  569. $this->assertSame(10, $max);
  570. $max = (new Query())
  571. ->from('customer')
  572. ->where(['group' => 'even'])
  573. ->min('status', $db);
  574. $this->assertSame(2, $max);
  575. $max = (new Query())
  576. ->from('customer')
  577. ->where(['group' => 'even'])
  578. ->sum('status', $db);
  579. $this->assertSame(30, $max);
  580. $max = (new Query())
  581. ->from('customer')
  582. ->where(['group' => 'even'])
  583. ->average('status', $db);
  584. $this->assertEquals(6, $max);
  585. }
  586. }