| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456 |
- <?php
- declare(strict_types=1);
- /**
- * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
- * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- *
- * Licensed under The Open Group Test Suite License
- * Redistributions of files must retain the above copyright notice.
- *
- * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
- * @link https://cakephp.org CakePHP(tm) Project
- * @since 4.1.0
- * @license https://opensource.org/licenses/mit-license.php MIT License
- */
- namespace Cake\Test\TestCase\Database\Expression;
- use Cake\Database\Expression\AggregateExpression;
- use Cake\Database\Expression\IdentifierExpression;
- use Cake\Database\Expression\OrderByExpression;
- use Cake\Database\Expression\OrderClauseExpression;
- use Cake\Database\Expression\QueryExpression;
- use Cake\Database\Expression\WindowExpression;
- use Cake\Database\ValueBinder;
- use Cake\TestSuite\TestCase;
- /**
- * Tests WindowExpression class
- */
- class WindowExpressionTest extends TestCase
- {
- /**
- * Tests an empty window expression
- */
- public function testEmptyWindow(): void
- {
- $w = new WindowExpression();
- $this->assertSame('', $w->sql(new ValueBinder()));
- $w->partition('')->orderBy([]);
- $this->assertSame('', $w->sql(new ValueBinder()));
- }
- /**
- * Tests windows with partitions
- */
- public function testPartitions(): void
- {
- $w = (new WindowExpression())->partition('test');
- $this->assertEqualsSql(
- 'PARTITION BY test',
- $w->sql(new ValueBinder())
- );
- $w->partition(new IdentifierExpression('identifier'));
- $this->assertEqualsSql(
- 'PARTITION BY test, identifier',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->partition(new AggregateExpression('MyAggregate', ['param']));
- $this->assertEqualsSql(
- 'PARTITION BY MyAggregate(:param0)',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->partition(function (QueryExpression $expr) {
- return $expr->add(new AggregateExpression('MyAggregate', ['param']));
- });
- $this->assertEqualsSql(
- 'PARTITION BY MyAggregate(:param0)',
- $w->sql(new ValueBinder())
- );
- }
- /**
- * Tests windows with order by
- */
- public function testOrderBy(): void
- {
- $w = (new WindowExpression())->orderBy('test');
- $this->assertEqualsSql(
- 'ORDER BY test',
- $w->sql(new ValueBinder())
- );
- $w->orderBy(['test2' => 'DESC']);
- $this->assertEqualsSql(
- 'ORDER BY test, test2 DESC',
- $w->sql(new ValueBinder())
- );
- $w->partition('test');
- $this->assertEqualsSql(
- 'PARTITION BY test ORDER BY test, test2 DESC',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())
- ->orderBy(function () {
- return 'test';
- })
- ->orderBy(function (QueryExpression $expr) {
- return [$expr->add('test2'), new OrderClauseExpression(new IdentifierExpression('test3'), 'DESC')];
- });
- $this->assertEqualsSql(
- 'ORDER BY test, test2, test3 DESC',
- $w->sql(new ValueBinder())
- );
- }
- public function testOrderDeprecated(): void
- {
- $w = (new WindowExpression())->order('test');
- $this->assertEqualsSql(
- 'ORDER BY test',
- $w->sql(new ValueBinder())
- );
- }
- /**
- * Tests windows with range frames
- */
- public function testRange(): void
- {
- $w = (new WindowExpression())->range(null);
- $this->assertEqualsSql(
- 'RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->range(0);
- $this->assertEqualsSql(
- 'RANGE BETWEEN CURRENT ROW AND CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->range(2);
- $this->assertEqualsSql(
- 'RANGE BETWEEN 2 PRECEDING AND CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->range(null, null);
- $this->assertEqualsSql(
- 'RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->range(0, null);
- $this->assertEqualsSql(
- 'RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->range(0, 0);
- $this->assertEqualsSql(
- 'RANGE BETWEEN CURRENT ROW AND CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->range(1, 2);
- $this->assertEqualsSql(
- 'RANGE BETWEEN 1 PRECEDING AND 2 FOLLOWING',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->range("'1 day'", "'10 days'");
- $this->assertRegExpSql(
- "RANGE BETWEEN '1 day' PRECEDING AND '10 days' FOLLOWING",
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->range(new QueryExpression("'1 day'"), new QueryExpression("'10 days'"));
- $this->assertRegExpSql(
- "RANGE BETWEEN '1 day' PRECEDING AND '10 days' FOLLOWING",
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->frame(
- WindowExpression::RANGE,
- 2,
- WindowExpression::PRECEDING,
- 1,
- WindowExpression::PRECEDING
- );
- $this->assertEqualsSql(
- 'RANGE BETWEEN 2 PRECEDING AND 1 PRECEDING',
- $w->sql(new ValueBinder())
- );
- }
- /**
- * Tests windows with rows frames
- */
- public function testRows(): void
- {
- $w = (new WindowExpression())->rows(null);
- $this->assertEqualsSql(
- 'ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->rows(0);
- $this->assertEqualsSql(
- 'ROWS BETWEEN CURRENT ROW AND CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->rows(2);
- $this->assertEqualsSql(
- 'ROWS BETWEEN 2 PRECEDING AND CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->rows(null, null);
- $this->assertEqualsSql(
- 'ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->rows(0, null);
- $this->assertEqualsSql(
- 'ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->rows(0, 0);
- $this->assertEqualsSql(
- 'ROWS BETWEEN CURRENT ROW AND CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->rows(1, 2);
- $this->assertEqualsSql(
- 'ROWS BETWEEN 1 PRECEDING AND 2 FOLLOWING',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->frame(
- WindowExpression::ROWS,
- 2,
- WindowExpression::PRECEDING,
- 1,
- WindowExpression::PRECEDING
- );
- $b = new ValueBinder();
- $this->assertEqualsSql(
- 'ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING',
- $w->sql($b)
- );
- }
- /**
- * Tests windows with groups frames
- */
- public function testGroups(): void
- {
- $w = (new WindowExpression())->groups(null);
- $this->assertEqualsSql(
- 'GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->groups(0);
- $this->assertEqualsSql(
- 'GROUPS BETWEEN CURRENT ROW AND CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->groups(2);
- $this->assertEqualsSql(
- 'GROUPS BETWEEN 2 PRECEDING AND CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->groups(null, null);
- $this->assertEqualsSql(
- 'GROUPS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->groups(0, null);
- $this->assertEqualsSql(
- 'GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->groups(0, 0);
- $this->assertEqualsSql(
- 'GROUPS BETWEEN CURRENT ROW AND CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->groups(1, 2);
- $this->assertEqualsSql(
- 'GROUPS BETWEEN 1 PRECEDING AND 2 FOLLOWING',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->frame(
- WindowExpression::GROUPS,
- 2,
- WindowExpression::PRECEDING,
- 1,
- WindowExpression::PRECEDING
- );
- $b = new ValueBinder();
- $this->assertEqualsSql(
- 'GROUPS BETWEEN 2 PRECEDING AND 1 PRECEDING',
- $w->sql($b)
- );
- }
- /**
- * Tests windows with frame exclusion
- */
- public function testExclusion(): void
- {
- $w = (new WindowExpression())->excludeCurrent();
- $this->assertEqualsSql(
- '',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->range(null)->excludeCurrent();
- $this->assertEqualsSql(
- 'RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->range(null)->excludeGroup();
- $this->assertEqualsSql(
- 'RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE GROUP',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->range(null)->excludeTies();
- $this->assertEqualsSql(
- 'RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE TIES',
- $w->sql(new ValueBinder())
- );
- }
- /**
- * Tests windows with partition, order and frames
- */
- public function testCombined(): void
- {
- $w = (new WindowExpression())->partition('test')->range(null);
- $this->assertEqualsSql(
- 'PARTITION BY test RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->orderBy('test')->range(null);
- $this->assertEqualsSql(
- 'ORDER BY test RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->partition('test')->orderBy('test')->range(null);
- $this->assertEqualsSql(
- 'PARTITION BY test ORDER BY test RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- $w = (new WindowExpression())->partition('test')->orderBy('test')->range(null)->excludeCurrent();
- $this->assertEqualsSql(
- 'PARTITION BY test ORDER BY test RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROW',
- $w->sql(new ValueBinder())
- );
- }
- /**
- * Tests named windows
- */
- public function testNamedWindow(): void
- {
- $w = new WindowExpression();
- $this->assertFalse($w->isNamedOnly());
- $w->name('name');
- $this->assertTrue($w->isNamedOnly());
- $this->assertEqualsSql(
- 'name',
- $w->sql(new ValueBinder())
- );
- $w->name('new_name');
- $this->assertEqualsSql(
- 'new_name',
- $w->sql(new ValueBinder())
- );
- $w->orderBy('test');
- $this->assertFalse($w->isNamedOnly());
- $this->assertEqualsSql(
- 'new_name ORDER BY test',
- $w->sql(new ValueBinder())
- );
- }
- /**
- * Tests traversing window expressions.
- */
- public function testTraverse(): void
- {
- $w = (new WindowExpression('test1'))
- ->partition('test2')
- ->orderBy('test3')
- ->range(new QueryExpression("'1 day'"));
- $expressions = [];
- $w->traverse(function ($expression) use (&$expressions): void {
- $expressions[] = $expression;
- });
- $this->assertEquals(new IdentifierExpression('test1'), $expressions[0]);
- $this->assertEquals(new IdentifierExpression('test2'), $expressions[1]);
- $this->assertEquals((new OrderByExpression())->add('test3'), $expressions[2]);
- $this->assertEquals(new QueryExpression("'1 day'"), $expressions[3]);
- $w->range(new QueryExpression("'1 day'"), new QueryExpression("'10 days'"));
- $expressions = [];
- $w->traverse(function ($expression) use (&$expressions): void {
- $expressions[] = $expression;
- });
- $this->assertEquals(new QueryExpression("'1 day'"), $expressions[3]);
- $this->assertEquals(new QueryExpression("'10 days'"), $expressions[4]);
- }
- /**
- * Tests cloning window expressions
- */
- public function testCloning(): void
- {
- $w1 = (new WindowExpression())->name('test');
- $w2 = (clone $w1)->name('test2');
- $this->assertNotSame($w1->sql(new ValueBinder()), $w2->sql(new ValueBinder()));
- $w1 = (new WindowExpression())->partition('test');
- $w2 = (clone $w1)->partition('new');
- $this->assertNotSame($w1->sql(new ValueBinder()), $w2->sql(new ValueBinder()));
- $w1 = (new WindowExpression())->orderBy('test');
- $w2 = (clone $w1)->orderBy('new');
- $this->assertNotSame($w1->sql(new ValueBinder()), $w2->sql(new ValueBinder()));
- $w1 = (new WindowExpression())->rows(0, null);
- $w2 = (clone $w1)->rows(0, 0);
- $this->assertNotSame($w1->sql(new ValueBinder()), $w2->sql(new ValueBinder()));
- }
- }
|