WindowQueryTest.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  5. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  6. *
  7. * Licensed under The Open Group Test Suite License
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 4.1.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\Database\QueryTests;
  16. use Cake\Database\Driver\Mysql;
  17. use Cake\Database\Driver\Sqlite;
  18. use Cake\Database\Driver\Sqlserver;
  19. use Cake\Database\DriverInterface;
  20. use Cake\Database\Expression\QueryExpression;
  21. use Cake\Database\Expression\WindowExpression;
  22. use Cake\Database\Query;
  23. use Cake\Datasource\ConnectionManager;
  24. use Cake\TestSuite\TestCase;
  25. use RuntimeException;
  26. /**
  27. * Tests WindowExpression class
  28. */
  29. class WindowQueryTest extends TestCase
  30. {
  31. protected $fixtures = [
  32. 'core.Comments',
  33. ];
  34. /**
  35. * @var \Cake\Database\Connection
  36. */
  37. protected $connection = null;
  38. /**
  39. * @var bool
  40. */
  41. protected $autoQuote;
  42. /**
  43. * @var bool
  44. */
  45. protected $skipTests = false;
  46. public function setUp(): void
  47. {
  48. parent::setUp();
  49. $this->connection = ConnectionManager::get('test');
  50. $this->autoQuote = $this->connection->getDriver()->isAutoQuotingEnabled();
  51. $driver = $this->connection->getDriver();
  52. if (
  53. $driver instanceof Mysql ||
  54. $driver instanceof Sqlite
  55. ) {
  56. $this->skipTests = !$this->connection->getDriver()->supports(DriverInterface::FEATURE_WINDOW);
  57. } else {
  58. $this->skipTests = false;
  59. }
  60. }
  61. public function tearDown(): void
  62. {
  63. parent::tearDown();
  64. }
  65. /**
  66. * Tests window sql generation.
  67. */
  68. public function testWindowSql(): void
  69. {
  70. $query = new Query($this->connection);
  71. $sql = $query
  72. ->select('*')
  73. ->window('name', new WindowExpression())
  74. ->sql();
  75. $this->assertRegExpSql('SELECT \* WINDOW <name> AS \(\)', $sql, !$this->autoQuote);
  76. $sql = $query
  77. ->window('name2', new WindowExpression('name'))
  78. ->sql();
  79. $this->assertRegExpSql('SELECT \* WINDOW <name> AS \(\), <name2> AS \(<name>\)', $sql, !$this->autoQuote);
  80. $sql = $query
  81. ->window('name', function ($window, $query) {
  82. return $window->name('name3');
  83. }, true)
  84. ->sql();
  85. $this->assertEqualsSql('SELECT * WINDOW name AS (name3)', $sql);
  86. }
  87. public function testMissingWindow(): void
  88. {
  89. $this->expectException(RuntimeException::class);
  90. $this->expectExceptionMessage('You must return a `WindowExpression`');
  91. (new Query($this->connection))->window('name', function () {
  92. return new QueryExpression();
  93. });
  94. }
  95. public function testPartitions(): void
  96. {
  97. $this->skipIf($this->skipTests);
  98. $query = new Query($this->connection);
  99. $result = $query
  100. ->select(['num_rows' => $query->func()->count('*')->over()])
  101. ->from('comments')
  102. ->execute()
  103. ->fetchAll();
  104. $this->assertCount(6, $result);
  105. $query = new Query($this->connection);
  106. $result = $query
  107. ->select(['num_rows' => $query->func()->count('*')->partition('article_id')])
  108. ->from('comments')
  109. ->order(['article_id'])
  110. ->execute()
  111. ->fetchAll('assoc');
  112. $this->assertEquals(4, $result[0]['num_rows']);
  113. $query = new Query($this->connection);
  114. $result = $query
  115. ->select(['num_rows' => $query->func()->count('*')->partition('article_id')->order('updated')])
  116. ->from('comments')
  117. ->order(['updated'])
  118. ->execute()
  119. ->fetchAll('assoc');
  120. $this->assertEquals(1, $result[0]['num_rows']);
  121. $this->assertEquals(4, $result[3]['num_rows']);
  122. $this->assertEquals(1, $result[4]['num_rows']);
  123. }
  124. /**
  125. * Tests adding named windows to the query.
  126. */
  127. public function testNamedWindow(): void
  128. {
  129. $skip = $this->skipTests;
  130. if (!$skip) {
  131. $skip = $this->connection->getDriver() instanceof Sqlserver;
  132. }
  133. $this->skipIf($skip);
  134. $query = new Query($this->connection);
  135. $result = $query
  136. ->select(['num_rows' => $query->func()->count('*')->over('window1')])
  137. ->from('comments')
  138. ->window('window1', (new WindowExpression())->partition('article_id'))
  139. ->order(['article_id'])
  140. ->execute()
  141. ->fetchAll('assoc');
  142. $this->assertEquals(4, $result[0]['num_rows']);
  143. }
  144. public function testWindowChaining(): void
  145. {
  146. $skip = $this->skipTests;
  147. if (!$skip) {
  148. $driver = $this->connection->getDriver();
  149. $skip = $driver instanceof Sqlserver;
  150. if ($driver instanceof Sqlite) {
  151. $skip = version_compare($driver->version(), '3.28.0', '<');
  152. }
  153. }
  154. $this->skipIf($skip);
  155. $query = new Query($this->connection);
  156. $result = $query
  157. ->select(['num_rows' => $query->func()->count('*')->over('window2')])
  158. ->from('comments')
  159. ->window('window1', (new WindowExpression())->partition('article_id'))
  160. ->window('window2', new WindowExpression('window1'))
  161. ->order(['article_id'])
  162. ->execute()
  163. ->fetchAll('assoc');
  164. $this->assertEquals(4, $result[0]['num_rows']);
  165. }
  166. }