-
-
Notifications
You must be signed in to change notification settings - Fork 102
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add GroupKeyword class to fix postgres GROUP BY
- Loading branch information
1 parent
286e464
commit 48d61a0
Showing
3 changed files
with
166 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' | ||
); | ||
} | ||
} |