From 57ef5f5aeb6a7a2380c9cc1e51582200b11fa2d2 Mon Sep 17 00:00:00 2001 From: beberlei Date: Thu, 11 Feb 2010 18:59:58 +0000 Subject: [PATCH] [2.0] Added DQL Functions and Aggregate Functional Test-Case and fixed two small bugs in DQL Parser that came to light, also it seems that some of the functions are not supported by Oracle and Sqlite and some cases of SUBSTRING and TRIM produce bugs on MySQL. --- .../ORM/Query/AST/Functions/AbsFunction.php | 2 +- .../ORM/Query/AST/Functions/ModFunction.php | 4 +- .../Tests/ORM/Functional/AllTests.php | 1 + .../ORM/Functional/QueryDqlFunctionTest.php | 239 ++++++++++++++++++ 4 files changed, 243 insertions(+), 3 deletions(-) create mode 100644 tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php diff --git a/lib/Doctrine/ORM/Query/AST/Functions/AbsFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/AbsFunction.php index 040ec59e0..f1373201e 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/AbsFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/AbsFunction.php @@ -55,7 +55,7 @@ class AbsFunction extends FunctionNode { $lexer = $parser->getLexer(); - $parser->match(Lexer::T_ABS); + $parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_OPEN_PARENTHESIS); $this->simpleArithmeticExpression = $parser->SimpleArithmeticExpression(); diff --git a/lib/Doctrine/ORM/Query/AST/Functions/ModFunction.php b/lib/Doctrine/ORM/Query/AST/Functions/ModFunction.php index 46af27fbf..3c0f1dc87 100644 --- a/lib/Doctrine/ORM/Query/AST/Functions/ModFunction.php +++ b/lib/Doctrine/ORM/Query/AST/Functions/ModFunction.php @@ -46,9 +46,9 @@ class ModFunction extends FunctionNode { //TODO: Use platform to get SQL return 'MOD(' - . $sqlWalker->walkSimpleArithmeticExpression($this->_firstSimpleArithmeticExpression) + . $sqlWalker->walkSimpleArithmeticExpression($this->firstSimpleArithmeticExpression) . ', ' - . $sqlWalker->walkSimpleArithmeticExpression($this->_secondSimpleArithmeticExpression) + . $sqlWalker->walkSimpleArithmeticExpression($this->secondSimpleArithmeticExpression) . ')'; } diff --git a/tests/Doctrine/Tests/ORM/Functional/AllTests.php b/tests/Doctrine/Tests/ORM/Functional/AllTests.php index 0c58aff17..e3c921778 100644 --- a/tests/Doctrine/Tests/ORM/Functional/AllTests.php +++ b/tests/Doctrine/Tests/ORM/Functional/AllTests.php @@ -30,6 +30,7 @@ class AllTests $suite->addTestSuite('Doctrine\Tests\ORM\Functional\QueryCacheTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Functional\ResultCacheTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Functional\QueryTest'); + $suite->addTestSuite('Doctrine\Tests\ORM\Functional\QueryDqlFunctionTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Functional\OneToOneUnidirectionalAssociationTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Functional\OneToOneBidirectionalAssociationTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Functional\OneToManyBidirectionalAssociationTest'); diff --git a/tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php b/tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php new file mode 100644 index 000000000..f0ed7e555 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/QueryDqlFunctionTest.php @@ -0,0 +1,239 @@ +useModelSet('company'); + parent::setUp(); + + $this->generateFixture(); + } + + public function testAggregateSum() + { + $salarySum = $this->_em->createQuery('SELECT SUM(m.salary) AS salary FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getSingleResult(); + + $this->assertEquals(1500000, $salarySum['salary']); + } + + public function testAggregateAvg() + { + $salaryAvg = $this->_em->createQuery('SELECT AVG(m.salary) AS salary FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getSingleResult(); + + $this->assertEquals(375000, round($salaryAvg['salary'], 0)); + } + + public function testAggregateMin() + { + $salary = $this->_em->createQuery('SELECT MIN(m.salary) AS salary FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getSingleResult(); + + $this->assertEquals(100000, $salary['salary']); + } + + public function testAggregateMax() + { + $salary = $this->_em->createQuery('SELECT MAX(m.salary) AS salary FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getSingleResult(); + + $this->assertEquals(800000, $salary['salary']); + } + + public function testAggregateCount() + { + $managerCount = $this->_em->createQuery('SELECT COUNT(m.id) AS managers FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getSingleResult(); + + $this->assertEquals(4, $managerCount['managers']); + } + + public function testFunctionAbs() + { + $arg = $this->_em->createQuery('SELECT m, ABS(m.salary * -1) AS abs FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getResult(); + + $this->assertEquals(4, count($arg)); + $this->assertEquals(100000, $arg[0]['abs']); + $this->assertEquals(200000, $arg[1]['abs']); + $this->assertEquals(400000, $arg[2]['abs']); + $this->assertEquals(800000, $arg[3]['abs']); + } + + public function testFunctionConcat() + { + $arg = $this->_em->createQuery('SELECT m, CONCAT(m.name, m.department) AS namedep FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getArrayResult(); + + $this->assertEquals(4, count($arg)); + $this->assertEquals('Roman B.IT', $arg[0]['namedep']); + $this->assertEquals('Benjamin E.HR', $arg[1]['namedep']); + $this->assertEquals('Guilherme B.Complaint Department', $arg[2]['namedep']); + $this->assertEquals('Jonathan W.Administration', $arg[3]['namedep']); + } + + public function testFunctionLength() + { + $result = $this->_em->createQuery('SELECT m, LENGTH(CONCAT(m.name, m.department)) AS namedeplength FROM Doctrine\Tests\Models\Company\CompanyManager m') + ->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals(10, $result[0]['namedeplength']); + $this->assertEquals(13, $result[1]['namedeplength']); + $this->assertEquals(32, $result[2]['namedeplength']); + $this->assertEquals(25, $result[3]['namedeplength']); + } + + public function testFunctionLocate() + { + $this->markTestIncomplete('Locate is not working equally across platforms, needs some work.'); + + $result = $this->_em->createQuery("SELECT m, LOCATE(m.name, 'e') AS locate FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals(0, $result[0]['locate']); + $this->assertEquals(2, $result[1]['locate']); + $this->assertEquals(10, $result[2]['locate']); + $this->assertEquals(25, $result[3]['locate']); + } + + public function testFunctionLower() + { + $result = $this->_em->createQuery("SELECT m, LOWER(m.name) AS lowername FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals('roman b.', $result[0]['lowername']); + $this->assertEquals('benjamin e.', $result[1]['lowername']); + $this->assertEquals('guilherme b.', $result[2]['lowername']); + $this->assertEquals('jonathan w.', $result[3]['lowername']); + } + + public function testFunctionMod() + { + $this->markTestSkipped('MOD does not exist on SqLite'); + + $result = $this->_em->createQuery("SELECT m, MOD(m.salary, 3500) AS amod FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals(2000, $result[0]['amod']); + $this->assertEquals(500, $result[1]['amod']); + $this->assertEquals(1000, $result[2]['amod']); + $this->assertEquals(2000, $result[3]['amod']); + } + + public function testFunctionSqrt() + { + $this->markTestSkipped('SQRT does not exist on SqLite'); + + $result = $this->_em->createQuery("SELECT m, SQRT(m.salary) AS sqrtsalary FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals(316, round($result[0]['sqrtsalary'])); + $this->assertEquals(447, round($result[1]['sqrtsalary'])); + $this->assertEquals(632, round($result[2]['sqrtsalary'])); + $this->assertEquals(894, round($result[3]['sqrtsalary'])); + } + + public function testFunctionUpper() + { + $result = $this->_em->createQuery("SELECT m, UPPER(m.name) AS uppername FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals('ROMAN B.', $result[0]['uppername']); + $this->assertEquals('BENJAMIN E.', $result[1]['uppername']); + $this->assertEquals('GUILHERME B.', $result[2]['uppername']); + $this->assertEquals('JONATHAN W.', $result[3]['uppername']); + } + + public function testFunctionSubstring() + { + $this->markTestSkipped('SUBSTRING does not exist on Oracle and Sqlite.'); + + $result = $this->_em->createQuery("SELECT m, SUBSTRING(m.name, 1, 3) AS str1 FROM Doctrine\Tests\Models\Company\CompanyManager m") + ->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals('Rom', $result[0]['str1']); + $this->assertEquals('Ben', $result[1]['str1']); + $this->assertEquals('Gui', $result[2]['str1']); + $this->assertEquals('Jon', $result[3]['str1']); + } + + public function testFunctionTrim() + { + $this->markTestIncomplete('Trim has problems on MySql (3rd Case).'); + + $dql = "SELECT m, TRIM(TRAILING '.' FROM m.name) AS str1, ". + " TRIM(LEADING '.' FROM m.name) AS str2, TRIM(CONCAT(' ', CONCAT(m.name, ' '))) AS str3 ". + "FROM Doctrine\Tests\Models\Company\CompanyManager m"; + + $result = $this->_em->createQuery($dql) + ->getArrayResult(); + + $this->assertEquals(4, count($result)); + $this->assertEquals('Roman B', $result[0]['str1']); + $this->assertEquals('Benjamin E', $result[1]['str1']); + $this->assertEquals('Guilherme B', $result[2]['str1']); + $this->assertEquals('Jonathan W', $result[3]['str1']); + $this->assertEquals('Roman B.', $result[0]['str2']); + $this->assertEquals('Benjamin E.', $result[1]['str2']); + $this->assertEquals('Guilherme B.', $result[2]['str2']); + $this->assertEquals('Jonathan W.', $result[3]['str2']); + $this->assertEquals('Roman B.', $result[0]['str3']); + $this->assertEquals('Benjamin E.', $result[1]['str3']); + $this->assertEquals('Guilherme B.', $result[2]['str3']); + $this->assertEquals('Jonathan W.', $result[3]['str3']); + } + + protected function generateFixture() + { + $manager1 = new CompanyManager(); + $manager1->setName('Roman B.'); + $manager1->setTitle('Foo'); + $manager1->setDepartment('IT'); + $manager1->setSalary(100000); + + $manager2 = new CompanyManager(); + $manager2->setName('Benjamin E.'); + $manager2->setTitle('Foo'); + $manager2->setDepartment('HR'); + $manager2->setSalary(200000); + + $manager3 = new CompanyManager(); + $manager3->setName('Guilherme B.'); + $manager3->setTitle('Foo'); + $manager3->setDepartment('Complaint Department'); + $manager3->setSalary(400000); + + $manager4 = new CompanyManager(); + $manager4->setName('Jonathan W.'); + $manager4->setTitle('Foo'); + $manager4->setDepartment('Administration'); + $manager4->setSalary(800000); + + $this->_em->persist($manager1); + $this->_em->persist($manager2); + $this->_em->persist($manager3); + $this->_em->persist($manager4); + $this->_em->flush(); + $this->_em->clear(); + } +} \ No newline at end of file