Skip to content

Commit

Permalink
Add GroupKeyword class to fix postgres GROUP BY
Browse files Browse the repository at this point in the history
  • Loading branch information
JoseNetoooo committed May 31, 2017
1 parent 286e464 commit 48d61a0
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 1 deletion.
141 changes: 141 additions & 0 deletions src/Components/GroupKeyword.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php

/**
* `GROUP BY` keyword parser.
*/

namespace PhpMyAdmin\SqlParser\Components;

use PhpMyAdmin\SqlParser\Component;
use PhpMyAdmin\SqlParser\Parser;
use PhpMyAdmin\SqlParser\Token;
use PhpMyAdmin\SqlParser\TokensList;

/**
* `GROUP BY` keyword parser.
*
* @category Keywords
*
* @license https://www.gnu.org/licenses/gpl-2.0.txt GPL-2.0+
*/
class GroupKeyword extends Component
{
/**
* The expression that is used for ordering.
*
* @var Expression
*/
public $expr;

/**
* The order type.
*
* @var string
*/
public $type;

/**
* Constructor.
*
* @param Expression $expr the expression that we are sorting by
* @param string $type the sorting type
*/
public function __construct($expr = null, $type = '')
{
$this->expr = $expr;
$this->type = $type;
}

/**
* @param Parser $parser the parser that serves as context
* @param TokensList $list the list of tokens that are being parsed
* @param array $options parameters for parsing
*
* @return GroupKeyword[]
*/
public static function parse(Parser $parser, TokensList $list, array $options = array())
{
$ret = array();

$expr = new self();

/**
* The state of the parser.
*
* Below are the states of the parser.
*
* 0 --------------------[ expression ]-------------------> 1
*
* 1 ------------------------[ , ]------------------------> 0
* 1 -------------------[ ASC / DESC ]--------------------> 1
*
* @var int
*/
$state = 0;

for (; $list->idx < $list->count; ++$list->idx) {
/**
* Token parsed at this moment.
*
* @var Token
*/
$token = $list->tokens[$list->idx];

// End of statement.
if ($token->type === Token::TYPE_DELIMITER) {
break;
}

// Skipping whitespaces and comments.
if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) {
continue;
}

if ($state === 0) {
$expr->expr = Expression::parse($parser, $list);
$state = 1;
} elseif ($state === 1) {
if (($token->type === Token::TYPE_KEYWORD)
&& (($token->keyword === 'ASC') || ($token->keyword === 'DESC'))
) {
$expr->type = $token->keyword;
} elseif (($token->type === Token::TYPE_OPERATOR)
&& ($token->value === ',')
) {
if (!empty($expr->expr)) {
$ret[] = $expr;
}
$expr = new self();
$state = 0;
} else {
break;
}
}
}

// Last iteration was not processed.
if (!empty($expr->expr)) {
$ret[] = $expr;
}

--$list->idx;

return $ret;
}

/**
* @param GroupKeyword|GroupKeyword[] $component the component to be built
* @param array $options parameters for building
*
* @return string
*/
public static function build($component, array $options = array())
{
if (is_array($component)) {
return implode(', ', $component);
}

return trim($component->expr . ' ' . $component->type);

}
}
2 changes: 1 addition & 1 deletion src/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ class Parser extends Core
'options' => array('field' => 'table'),
),
'GROUP BY' => array(
'class' => 'PhpMyAdmin\\SqlParser\\Components\\OrderKeyword',
'class' => 'PhpMyAdmin\\SqlParser\\Components\\GroupKeyword',
'field' => 'group',
),
'HAVING' => array(
Expand Down
24 changes: 24 additions & 0 deletions tests/Components/GroupKeywordTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace PhpMyAdmin\SqlParser\Tests\Components;

use PhpMyAdmin\SqlParser\Components\Expression;
use PhpMyAdmin\SqlParser\Components\GroupKeyword;
use PhpMyAdmin\SqlParser\Tests\TestCase;

class GroupKeywordTest extends TestCase
{
public function testBuild()
{
$this->assertEquals(
GroupKeyword::build(
array(
new GroupKeyword(new Expression('a'), 'ASC'),
new GroupKeyword(new Expression('b'), 'DESC'),
new GroupKeyword(new Expression('c')),
)
),
'a ASC, b DESC, c'
);
}
}

0 comments on commit 48d61a0

Please sign in to comment.