From f277eef6eab0fdac4e1085eecd8ebd9ece2b610e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20L=C3=A9v=C3=AAque?= Date: Mon, 2 Oct 2017 12:03:26 +0200 Subject: [PATCH 1/2] Add support second, minute, week, year on DATE_ADD and DATE_SUB --- .../Query/AST/Functions/DateAddFunction.php | 19 ++++++++-- .../Query/AST/Functions/DateSubFunction.php | 23 ++++++++++-- .../ORM/Functional/QueryDqlFunctionTest.php | 36 +++++++++++++++++++ 3 files changed, 73 insertions(+), 5 deletions(-) diff --git a/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php index 859426f08..edec7f987 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/DateAddFunction.php @@ -51,7 +51,11 @@ class DateAddFunction extends FunctionNode $this->firstDateExpression->dispatch($sqlWalker), $this->intervalExpression->dispatch($sqlWalker) ); - + case 'minute': + return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddMinutesExpression( + $this->firstDateExpression->dispatch($sqlWalker), + $this->intervalExpression->dispatch($sqlWalker) + ); case 'hour': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddHourExpression( $this->firstDateExpression->dispatch($sqlWalker), @@ -62,16 +66,25 @@ class DateAddFunction extends FunctionNode $this->firstDateExpression->dispatch($sqlWalker), $this->intervalExpression->dispatch($sqlWalker) ); - + case 'week': + return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddWeeksExpression( + $this->firstDateExpression->dispatch($sqlWalker), + $this->intervalExpression->dispatch($sqlWalker) + ); case 'month': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddMonthExpression( $this->firstDateExpression->dispatch($sqlWalker), $this->intervalExpression->dispatch($sqlWalker) ); + case 'year': + return $sqlWalker->getConnection()->getDatabasePlatform()->getDateAddYearsExpression( + $this->firstDateExpression->dispatch($sqlWalker), + $this->intervalExpression->dispatch($sqlWalker) + ); default: throw QueryException::semanticalError( - 'DATE_ADD() only supports units of type second, hour, day and month.' + 'DATE_ADD() only supports units of type second, minute, hour, day, week, month and year.' ); } } diff --git a/lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php index a6415a286..8dcc13537 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/DateSubFunction.php @@ -40,6 +40,16 @@ class DateSubFunction extends DateAddFunction public function getSql(SqlWalker $sqlWalker) { switch (strtolower($this->unit->value)) { + case 'second': + return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubSecondsExpression( + $this->firstDateExpression->dispatch($sqlWalker), + $this->intervalExpression->dispatch($sqlWalker) + ); + case 'minute': + return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubMinutesExpression( + $this->firstDateExpression->dispatch($sqlWalker), + $this->intervalExpression->dispatch($sqlWalker) + ); case 'hour': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubHourExpression( $this->firstDateExpression->dispatch($sqlWalker), @@ -50,16 +60,25 @@ class DateSubFunction extends DateAddFunction $this->firstDateExpression->dispatch($sqlWalker), $this->intervalExpression->dispatch($sqlWalker) ); - + case 'week': + return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubWeeksExpression( + $this->firstDateExpression->dispatch($sqlWalker), + $this->intervalExpression->dispatch($sqlWalker) + ); case 'month': return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubMonthExpression( $this->firstDateExpression->dispatch($sqlWalker), $this->intervalExpression->dispatch($sqlWalker) ); + case 'year': + return $sqlWalker->getConnection()->getDatabasePlatform()->getDateSubYearsExpression( + $this->firstDateExpression->dispatch($sqlWalker), + $this->intervalExpression->dispatch($sqlWalker) + ); default: throw QueryException::semanticalError( - 'DATE_SUB() only supports units of type hour, day and month.' + 'DATE_SUB() only supports units of type second, minute, hour, day, week, month and year.' ); } } diff --git a/tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php b/tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php index 764b213dd..319612138 100644 --- a/tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php @@ -301,6 +301,24 @@ class QueryDqlFunctionTest extends OrmFunctionalTestCase $this->assertTrue(strtotime($arg[0]['add']) > 0); } + /** + * @group DDC-2938 + */ + public function testDateAddTime(): void + { + $arg = $this->_em->createQuery("SELECT DATE_ADD(CURRENT_TIMESTAMP(), 10, 'second') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + self::assertTrue(strtotime($arg[0]['add']) > 0); + + $arg = $this->_em->createQuery("SELECT DATE_ADD(CURRENT_TIMESTAMP(), 10, 'minute') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + self::assertTrue(strtotime($arg[0]['add']) > 0); + + $arg = $this->_em->createQuery("SELECT DATE_ADD(CURRENT_TIMESTAMP(), 10, 'hour') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + self::assertTrue(strtotime($arg[0]['add']) > 0); + } + public function testDateAddSecond() { $dql = "SELECT CURRENT_TIMESTAMP() now, DATE_ADD(CURRENT_TIMESTAMP(), 10, 'second') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m"; @@ -334,6 +352,24 @@ class QueryDqlFunctionTest extends OrmFunctionalTestCase $this->assertTrue(strtotime($arg[0]['add']) > 0); } + /** + * @group DDC-2938 + */ + public function testDateSubTime(): void + { + $arg = $this->_em->createQuery("SELECT DATE_SUB(CURRENT_TIMESTAMP(), 10, 'second') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + self::assertTrue(strtotime($arg[0]['add']) > 0); + + $arg = $this->_em->createQuery("SELECT DATE_SUB(CURRENT_TIMESTAMP(), 10, 'minute') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + self::assertTrue(strtotime($arg[0]['add']) > 0); + + $arg = $this->_em->createQuery("SELECT DATE_SUB(CURRENT_TIMESTAMP(), 10, 'hour') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + self::assertTrue(strtotime($arg[0]['add']) > 0); + } + /** * @group DDC-1213 */ From 59792654c0fd37bb974efa35d63328be36e59ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=ADs=20Cobucci?= Date: Mon, 30 Oct 2017 21:29:08 +0100 Subject: [PATCH 2/2] Improve tests for DATE_ADD and DATE_SUB So that we can do proper assertions and cover all the possibilities of the functions. --- .../ORM/Functional/QueryDqlFunctionTest.php | 108 ++++++++---------- 1 file changed, 46 insertions(+), 62 deletions(-) diff --git a/tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php b/tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php index 319612138..6c4152069 100644 --- a/tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php @@ -2,6 +2,7 @@ namespace Doctrine\Tests\ORM\Functional; +use Doctrine\ORM\AbstractQuery; use Doctrine\Tests\Models\Company\CompanyManager; use Doctrine\Tests\OrmFunctionalTestCase; @@ -176,7 +177,7 @@ class QueryDqlFunctionTest extends OrmFunctionalTestCase $this->assertEquals('Gui', $result[1]['str1']); $this->assertEquals('Jon', $result[2]['str1']); $this->assertEquals('Rom', $result[3]['str1']); - + $this->assertEquals('amin E.', $result[0]['str2']); $this->assertEquals('herme B.', $result[1]['str2']); $this->assertEquals('than W.', $result[2]['str2']); @@ -287,87 +288,70 @@ class QueryDqlFunctionTest extends OrmFunctionalTestCase /** * @group DDC-1014 - */ - public function testDateAdd() - { - $arg = $this->_em->createQuery("SELECT DATE_ADD(CURRENT_TIMESTAMP(), 10, 'day') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") - ->getArrayResult(); - - $this->assertTrue(strtotime($arg[0]['add']) > 0); - - $arg = $this->_em->createQuery("SELECT DATE_ADD(CURRENT_TIMESTAMP(), 10, 'month') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") - ->getArrayResult(); - - $this->assertTrue(strtotime($arg[0]['add']) > 0); - } - - /** * @group DDC-2938 + * + * @dataProvider dateAddSubProvider */ - public function testDateAddTime(): void + public function testDateAdd(string $unit, int $amount, int $expectedValue, int $delta = 0) : void { - $arg = $this->_em->createQuery("SELECT DATE_ADD(CURRENT_TIMESTAMP(), 10, 'second') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") - ->getArrayResult(); - self::assertTrue(strtotime($arg[0]['add']) > 0); + $query = sprintf( + 'SELECT CURRENT_TIMESTAMP() as now, DATE_ADD(CURRENT_TIMESTAMP(), %d, \'%s\') AS add FROM %s m', + $amount, + $unit, + CompanyManager::class + ); - $arg = $this->_em->createQuery("SELECT DATE_ADD(CURRENT_TIMESTAMP(), 10, 'minute') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") - ->getArrayResult(); - self::assertTrue(strtotime($arg[0]['add']) > 0); + $result = $this->_em->createQuery($query) + ->setMaxResults(1) + ->getSingleResult(AbstractQuery::HYDRATE_ARRAY); - $arg = $this->_em->createQuery("SELECT DATE_ADD(CURRENT_TIMESTAMP(), 10, 'hour') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") - ->getArrayResult(); - self::assertTrue(strtotime($arg[0]['add']) > 0); - } + self::assertArrayHasKey('now', $result); + self::assertArrayHasKey('add', $result); - public function testDateAddSecond() - { - $dql = "SELECT CURRENT_TIMESTAMP() now, DATE_ADD(CURRENT_TIMESTAMP(), 10, 'second') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m"; - $query = $this->_em->createQuery($dql)->setMaxResults(1); - $result = $query->getArrayResult(); + $diff = strtotime($result['add']) - strtotime($result['now']); - $this->assertCount(1, $result); - $this->assertArrayHasKey('now', $result[0]); - $this->assertArrayHasKey('add', $result[0]); - - $now = strtotime($result[0]['now']); - $add = strtotime($result[0]['add']); - $diff = $add - $now; - - $this->assertSQLEquals(10, $diff); + self::assertEquals($expectedValue, $diff, '', $delta); } /** * @group DDC-1014 + * @group DDC-2938 + * + * @dataProvider dateAddSubProvider */ - public function testDateSub() + public function testDateSub(string $unit, int $amount, int $expectedValue, int $delta = 0) : void { - $arg = $this->_em->createQuery("SELECT DATE_SUB(CURRENT_TIMESTAMP(), 10, 'day') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") - ->getArrayResult(); + $query = sprintf( + 'SELECT CURRENT_TIMESTAMP() as now, DATE_SUB(CURRENT_TIMESTAMP(), %d, \'%s\') AS sub FROM %s m', + $amount, + $unit, + CompanyManager::class + ); - $this->assertTrue(strtotime($arg[0]['add']) > 0); + $result = $this->_em->createQuery($query) + ->setMaxResults(1) + ->getSingleResult(AbstractQuery::HYDRATE_ARRAY); - $arg = $this->_em->createQuery("SELECT DATE_SUB(CURRENT_TIMESTAMP(), 10, 'month') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") - ->getArrayResult(); + self::assertArrayHasKey('now', $result); + self::assertArrayHasKey('sub', $result); - $this->assertTrue(strtotime($arg[0]['add']) > 0); + $diff = strtotime($result['now']) - strtotime($result['sub']); + + self::assertEquals($expectedValue, $diff, '', $delta); } - /** - * @group DDC-2938 - */ - public function testDateSubTime(): void + public function dateAddSubProvider() : array { - $arg = $this->_em->createQuery("SELECT DATE_SUB(CURRENT_TIMESTAMP(), 10, 'second') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") - ->getArrayResult(); - self::assertTrue(strtotime($arg[0]['add']) > 0); + $secondsInDay = 86400; - $arg = $this->_em->createQuery("SELECT DATE_SUB(CURRENT_TIMESTAMP(), 10, 'minute') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") - ->getArrayResult(); - self::assertTrue(strtotime($arg[0]['add']) > 0); - - $arg = $this->_em->createQuery("SELECT DATE_SUB(CURRENT_TIMESTAMP(), 10, 'hour') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") - ->getArrayResult(); - self::assertTrue(strtotime($arg[0]['add']) > 0); + return [ + 'year' => ['year', 1, 365 * $secondsInDay, 3 * $secondsInDay], + 'month' => ['month', 1, 30 * $secondsInDay, 2 * $secondsInDay], + 'week' => ['week', 1, 7 * $secondsInDay, $secondsInDay], + 'hour' => ['hour', 1, 3600], + 'minute' => ['minute', 1, 60], + 'second' => ['second', 10, 10], + ]; } /**