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..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,51 +288,70 @@ class QueryDqlFunctionTest extends OrmFunctionalTestCase /** * @group DDC-1014 + * @group DDC-2938 + * + * @dataProvider dateAddSubProvider */ - public function testDateAdd() + public function testDateAdd(string $unit, int $amount, int $expectedValue, int $delta = 0) : void { - $arg = $this->_em->createQuery("SELECT DATE_ADD(CURRENT_TIMESTAMP(), 10, 'day') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") - ->getArrayResult(); + $query = sprintf( + 'SELECT CURRENT_TIMESTAMP() as now, DATE_ADD(CURRENT_TIMESTAMP(), %d, \'%s\') AS add 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_ADD(CURRENT_TIMESTAMP(), 10, 'month') AS add FROM Doctrine\Tests\Models\Company\CompanyManager m") - ->getArrayResult(); + self::assertArrayHasKey('now', $result); + self::assertArrayHasKey('add', $result); - $this->assertTrue(strtotime($arg[0]['add']) > 0); - } + $diff = strtotime($result['add']) - strtotime($result['now']); - 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(); - - $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); + } + + public function dateAddSubProvider() : array + { + $secondsInDay = 86400; + + 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], + ]; } /**