626 lines
19 KiB
PHP

<?php
/**
* Author: Nil Portugués Calderó <contact@nilportugues.com>
* Date: 9/12/14
* Time: 10:46 PM.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace NilPortugues\Tests\Sql\QueryBuilder\Builder\Syntax;
use NilPortugues\Sql\QueryBuilder\Syntax\Column;
use NilPortugues\Sql\QueryBuilder\Syntax\OrderBy;
use NilPortugues\Sql\QueryBuilder\Manipulation\Select;
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
/**
* Class SelectWriterTest.
*/
class SelectWriterTest extends \PHPUnit_Framework_TestCase
{
/**
* @var GenericBuilder
*/
private $writer;
/**
* @var Select
*/
private $query;
/**
* @var string
*/
private $exceptionClass = '\NilPortugues\Sql\QueryBuilder\Manipulation\QueryException';
/**
*
*/
protected function setUp()
{
$this->writer = new GenericBuilder();
$this->query = new Select();
}
/**
* @test
*/
public function itShouldBeCloneableWithoutKeepingReferences()
{
$query1 = new Select('user');
$query2 = clone $query1;
$query2->setTable('users');
$this->assertFalse($query1->getTable() == $query2->getTable());
}
/**
* @test
*/
public function itShouldBeConstructedWithConstructor()
{
$this->query = new Select('user');
$expected = 'SELECT user.* FROM user';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToWriteCommentInQuery()
{
$this->query = new Select('user');
$this->query->setComment('This is a comment');
$expected = <<<SQL
-- This is a comment
SELECT user.* FROM user
SQL;
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldThrowExceptionWhenGettingColumnsButNoTableIsSet()
{
$this->setExpectedException($this->exceptionClass);
$this->query = new Select();
$this->query->getColumns();
}
/**
* @test
*/
public function itShouldBeConstructedWithConstructorWithColumns()
{
$this->query = new Select('user', array('user_id', 'name'));
$expected = 'SELECT user.user_id, user.name FROM user';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldSelectAll()
{
$this->query->setTable('user');
$expected = 'SELECT user.* FROM user';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldSelectAllDistinct()
{
$this->query->setTable('user')->distinct();
$expected = 'SELECT DISTINCT user.* FROM user';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldSelectAllWithLimit1()
{
$this->query->setTable('user')->limit(1);
$expected = 'SELECT user.* FROM user LIMIT :v1, :v2';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 0);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldSelectAllWithLimit1Offset2()
{
$this->query->setTable('user')->limit(1, 2);
$expected = 'SELECT user.* FROM user LIMIT :v1, :v2';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldSelectAllGetFirst20()
{
$this->query->setTable('user')->limit(0, 20);
$expected = 'SELECT user.* FROM user LIMIT :v1, :v2';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 0, ':v2' => 20);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldAllowColumnAlias()
{
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id', // Alias -> column name
'username' => 'name',
'email' => 'email',
)
);
$expected = 'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email" FROM user';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldAllowColumnOrder()
{
$this->query
->setTable('user')
->orderBy('user_id', OrderBy::ASC);
$expected = 'SELECT user.* FROM user ORDER BY user.user_id ASC';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldAllowColumnOrderUsingColumnAlias()
{
$tableName = 'user';
$this->query
->setTable($tableName)
->setColumns(
array(
'userId' => 'user_id', // Alias -> column name
'username' => 'name',
'email' => 'email',
)
)
->orderBy('user_id', OrderBy::ASC)
->orderBy('email', OrderBy::DESC);
$expected =
'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email" FROM '.
'user ORDER BY user.user_id ASC, user.email DESC';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoALeftJoin()
{
$this->query
->setTable('user')
->leftJoin('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'));
$expected = 'SELECT user.*, news.title, news.body, news.created_at, news.updated_at FROM user LEFT JOIN '.
'news ON (news.author_id = user.user_id)';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoARightJoin()
{
$this->query
->setTable('user')
->rightJoin('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'));
$expected = 'SELECT user.*, news.title, news.body, news.created_at, news.updated_at FROM user RIGHT JOIN '.
'news ON (news.author_id = user.user_id)';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoAInnerJoin()
{
$this->query
->setTable('user')
->innerJoin('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'));
$expected = 'SELECT user.*, news.title, news.body, news.created_at, news.updated_at FROM user INNER JOIN '.
'news ON (news.author_id = user.user_id)';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoACrossJoin()
{
$this->query
->setTable('user')
->crossJoin('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'));
$expected = 'SELECT user.*, news.title, news.body, news.created_at, news.updated_at FROM user CROSS JOIN '.
'news ON (news.author_id = user.user_id)';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoALeftJoinWithOrderByOnJoinedTable()
{
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at',
)
)
->orderBy('user_id', OrderBy::DESC)
->leftJoin('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'))
->orderBy('created_at', OrderBy::DESC);
$expected = 'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email", user.created_at,'.
' news.title, news.body, news.created_at, news.updated_at FROM user LEFT JOIN news ON (news.author_id '.
'= user.user_id) ORDER BY user.user_id DESC, news.created_at DESC';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoAJoin()
{
$this->query
->setTable('user')
->join('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'));
$expected = 'SELECT user.*, news.title, news.body, news.created_at, news.updated_at FROM user JOIN '.
'news ON (news.author_id = user.user_id)';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoAJoinWithOrderByOnJoinedTable()
{
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at',
)
)
->orderBy('user_id', OrderBy::DESC)
->join('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'))
->orderBy('created_at', OrderBy::DESC);
$expected = 'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email", user.created_at,'.
' news.title, news.body, news.created_at, news.updated_at FROM user JOIN news ON (news.author_id ='.
' user.user_id) ORDER BY user.user_id DESC, news.created_at DESC';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoAJoinWithCustomColumns()
{
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at',
)
)
->orderBy('user_id', OrderBy::DESC)
->join('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'))
->orderBy('created_at', OrderBy::DESC)
->join('articles', new Column('news_id', 'article'), new Column('id', 'news'));
$expected = 'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email", user.created_at,'.
' news.title, news.body, news.created_at, news.updated_at FROM user JOIN news ON (news.author_id ='.
' user.user_id) JOIN articles ON (news.id = article.news_id) ORDER BY user.user_id DESC, news.created_at DESC';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToDoAnAddWithMultipleJoins()
{
$this->query->setTable('user');
for ($i = 1; $i <= 5; ++$i) {
//Select QueryInterface for "news" table
$select = new Select();
$select
->setTable('news'.$i)
->setColumns(array('title'.$i));
//Select query for user table, being joined with "newsX" select.
$this->query->addJoin($select, 'user_id', 'author_id'.$i);
}
$expected = 'SELECT user.*, news1.title1, news2.title2, news3.title3, news4.title4, news5.title5 '.
'FROM user JOIN news1 ON (news1.author_id1 = user.user_id) JOIN news2 ON (news2.author_id2 = user.user_id)'.
' JOIN news3 ON (news3.author_id3 = user.user_id) JOIN news4 ON (news4.author_id4 = user.user_id) '.
'JOIN news5 ON (news5.author_id5 = user.user_id)';
$this->assertSame($expected, $this->writer->write($this->query));
}
/**
* @test
*/
public function itShouldBeAbleToOn()
{
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at',
)
)
->orderBy('user_id', OrderBy::DESC)
->join('news', 'user_id', 'author_id', array('title', 'body', 'created_at', 'updated_at'))
->orderBy('created_at', OrderBy::DESC)
->on()
->eq('author_id', 1);
$this->query->limit(1, 10);
$expected = 'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email", user.created_at,'.
' news.title, news.body, news.created_at, news.updated_at FROM user JOIN news ON '.
'(news.author_id = user.user_id) AND (news.author_id = :v1) ORDER BY '.
'user.user_id DESC, news.created_at DESC LIMIT :v2, :v3';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 1, ':v3' => 10);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToCountTotalRows()
{
$this->query
->setTable('user')
->count()
->groupBy(array('user_id', 'name'))
->having()
->equals('user_id', 1)
->equals('user_id', 2);
$expected = 'SELECT COUNT(*) FROM user GROUP BY user.user_id, user.name HAVING (user.user_id = :v1) AND (user.user_id = :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToCountTotalRowsSettingDefaultColumn()
{
$this->query
->setTable('user')
->count('user_id')
->groupBy(array('user_id', 'name'))
->having()
->equals('user_id', 1)
->equals('user_id', 2);
$expected = 'SELECT COUNT(user.user_id) FROM user GROUP BY user.user_id, user.name HAVING (user.user_id = :v1) AND (user.user_id = :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToCountTotalRowsSettingDefaultColumnWithAlias()
{
$this->query
->setTable('user')
->count('user_id', 'total_users')
->groupBy(array('user_id', 'name'))
->having()
->equals('user_id', 1)
->equals('user_id', 2);
$expected = 'SELECT COUNT(user.user_id) AS "total_users" FROM user GROUP BY user.user_id, user.name HAVING (user.user_id = :v1) AND (user.user_id = :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldBeAbleToGroupByOperator()
{
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at',
)
)
->groupBy(array('user_id', 'name'))
->having()
->equals('user_id', 1)
->equals('user_id', 2);
$expected = 'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email", user.created_at'.
' FROM user GROUP BY user.user_id, user.name HAVING (user.user_id = :v1) AND (user.user_id = :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldThrowExceptionInvalidHavingConjunction()
{
$this->setExpectedException($this->exceptionClass);
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at',
)
)
->groupBy(array('user_id', 'name'))
->having('AAAAAAAAAAAAAAAA');
}
/**
* @test
*/
public function itShouldBeAbleToSetHavingOperatorToOr()
{
$this->query
->setTable('user')
->setColumns(
array(
'userId' => 'user_id',
'username' => 'name',
'email' => 'email',
'created_at',
)
)
->groupBy(array('user_id', 'name'))
->having('OR')
->equals('user_id', 1)
->equals('user_id', 2);
$expected = 'SELECT user.user_id AS "userId", user.name AS "username", user.email AS "email", user.created_at'.
' FROM user GROUP BY user.user_id, user.name HAVING (user.user_id = :v1) OR (user.user_id = :v2)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldAllowSelectQueryToActAsAColumn()
{
$table1 = new Select('Table1');
$table1
->where()
->equals('table1_id', 1);
$table2 = new Select('Table2');
$table2
->where()
->eq($table1, 2);
$expected = 'SELECT Table2.* FROM Table2 WHERE ((SELECT Table1.* FROM Table1 '.
'WHERE (Table1.table1_id = :v1)) = :v2)';
$this->assertSame($expected, $this->writer->write($table2));
$expected = array(':v1' => 1, ':v2' => 2);
$this->assertEquals($expected, $this->writer->getValues());
}
/**
* @test
*/
public function itShouldWriteJoin()
{
$this->query
->isJoin(true)
->setTable('user')
->on()
->equals('user_id', 1);
$expected = 'JOIN user ON (user.user_id = :v1)';
$this->assertSame($expected, $this->writer->write($this->query));
$expected = array(':v1' => 1);
$this->assertEquals($expected, $this->writer->getValues());
}
}