Skip to content

Commit 2385f3e

Browse files
authored
Merge pull request #18 from pfilsx/mathematical_functions
add basic mathematical functions + cast function
2 parents 78d1cde + c048dbd commit 2385f3e

File tree

7 files changed

+252
-0
lines changed

7 files changed

+252
-0
lines changed

docs/Functions-and-Operators.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
|-------------------------|-----------------------|-------------------------------------------------------------------------------------------------------------------------------|
66
| ARRAY_AGG() | ARRAY_AGG | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\ArrayAgg](../src/ORM/Query/AST/Functions/ArrayAgg.php) |
77
| ARRAY_TO_JSON() | ARRAY_TO_JSON | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\ArrayToJson](../src/ORM/Query/AST/Functions/ArrayToJson.php) |
8+
| CAST() | CAST | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\Cast](../src/ORM/Query/AST/Functions/Cast.php) |
9+
| CEIL() | CEIL | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\Ceil](../src/ORM/Query/AST/Functions/Ceil.php) |
10+
| COUNT() | COUNT | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\Count](../src/ORM/Query/AST/Functions/Count.php) |
11+
| FLOOR() | FLOOR | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\Floor](../src/ORM/Query/AST/Functions/Floor.php) |
812
| JSON_AGG() | JSON_AGG | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonAgg](../src/ORM/Query/AST/Functions/JsonAgg.php) |
913
| JSON_ARRAY_LENGTH() | JSON_ARRAY_LENGTH | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonArrayLength](../src/ORM/Query/AST/Functions/JsonArrayLength.php) |
1014
| JSONB_AGG() | JSONB_AGG | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonbAgg](../src/ORM/Query/AST/Functions/JsonbAgg.php) |
@@ -21,6 +25,8 @@
2125
| JSON_OBJECT_KEYS() | JSON_OBJECT_KEYS | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonObjectKeys](../src/ORM/Query/AST/Functions/JsonObjectKeys.php) |
2226
| PHRASETO_TSQUERY() | PHRASETO_TSQUERY | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\PhraseToTsQuery](../src/ORM/Query/AST/Functions/PhraseToTsQuery.php) |
2327
| PLAINTO_TSQUERY() | PLAINTO_TSQUERY | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\PlainToTsQuery](../src/ORM/Query/AST/Functions/PlainToTsQuery.php) |
28+
| RANDOM() | RANDOM | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\Random](../src/ORM/Query/AST/Functions/Random.php) |
29+
| ROUND() | ROUND | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\Round](../src/ORM/Query/AST/Functions/Round.php) |
2430
| STRING_AGG() | STRING_AGG | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\StringAgg](../src/ORM/Query/AST/Functions/StringAgg.php) |
2531
| ARRAY[] | ARRAY | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\ToArray](../src/ORM/Query/AST/Functions/ToArray.php) |
2632
| BIGINT[] | BIGINT_ARRAY | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\ToBigIntArray](../src/ORM/Query/AST/Functions/ToBigIntArray.php) |
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions;
6+
7+
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
8+
use Doctrine\ORM\Query\AST\Node;
9+
use Doctrine\ORM\Query\Lexer;
10+
use Doctrine\ORM\Query\Parser;
11+
use Doctrine\ORM\Query\SqlWalker;
12+
13+
/**
14+
* Implementation of PostgreSql CAST() function.
15+
*
16+
* @see https://www.postgresql.org/docs/current/sql-createcast.html
17+
*
18+
* @example CAST(entity.field AS text)
19+
*/
20+
final class Cast extends FunctionNode
21+
{
22+
public Node $source;
23+
24+
public string $type;
25+
26+
public function parse(Parser $parser): void
27+
{
28+
$parser->match(Lexer::T_IDENTIFIER);
29+
$parser->match(Lexer::T_OPEN_PARENTHESIS);
30+
$this->source = $parser->SimpleArithmeticExpression();
31+
32+
$parser->match(Lexer::T_AS);
33+
$parser->match(Lexer::T_IDENTIFIER);
34+
35+
$type = $parser->getLexer()->token['value'] ?? null;
36+
37+
if (!is_string($type)) {
38+
return;
39+
}
40+
41+
$this->type = $type;
42+
43+
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
44+
}
45+
46+
public function getSql(SqlWalker $sqlWalker): string
47+
{
48+
return \sprintf('CAST(%s as %s)', $this->source->dispatch($sqlWalker), $this->type);
49+
}
50+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions;
6+
7+
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
8+
use Doctrine\ORM\Query\AST\Node;
9+
use Doctrine\ORM\Query\Lexer;
10+
use Doctrine\ORM\Query\Parser;
11+
use Doctrine\ORM\Query\SqlWalker;
12+
13+
/**
14+
* Implementation of PostgreSql CEIL() function.
15+
*
16+
* @see https://www.postgresql.org/docs/current/functions-math.html#FUNCTIONS-MATH-FUNC-TABLE
17+
*
18+
* @example CEIL(entity.field)
19+
*/
20+
final class Ceil extends FunctionNode
21+
{
22+
private Node $field;
23+
24+
public function parse(Parser $parser): void
25+
{
26+
$parser->match(Lexer::T_IDENTIFIER);
27+
$parser->match(Lexer::T_OPEN_PARENTHESIS);
28+
29+
$this->field = $parser->StringPrimary();
30+
31+
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
32+
}
33+
34+
public function getSql(SqlWalker $sqlWalker): string
35+
{
36+
return "CEIL({$this->field->dispatch($sqlWalker)})";
37+
}
38+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions;
6+
7+
use Doctrine\DBAL\Types\Type;
8+
use Doctrine\DBAL\Types\Types;
9+
use Doctrine\ORM\Query\AST\AggregateExpression;
10+
use Doctrine\ORM\Query\AST\TypedExpression;
11+
use Doctrine\ORM\Query\Parser;
12+
use Doctrine\ORM\Query\SqlWalker;
13+
14+
/**
15+
* Implementation of PostgreSql COUNT() function with FILTER (WHERE) support.
16+
*
17+
* @see https://www.postgresql.org/docs/current/functions-aggregate.html#FUNCTIONS-AGGREGATE-TABLE
18+
*
19+
* @example COUNT(entity.field)
20+
* @example COUNT(DISTINCT entity.field)
21+
* @example COUNT(entity.field) FILTER (WHERE entity.field IS NOT NULL)
22+
* @example COUNT(DISTINCT entity.field) FILTER (WHERE entity.field IS NOT NULL)
23+
*/
24+
final class Count extends AbstractAggregateWithFilterFunction implements TypedExpression
25+
{
26+
private AggregateExpression $aggregateExpression;
27+
28+
public function parseFunction(Parser $parser): void
29+
{
30+
$this->aggregateExpression = $parser->AggregateExpression();
31+
}
32+
33+
public function getFunctionSql(SqlWalker $sqlWalker): string
34+
{
35+
return $this->aggregateExpression->dispatch($sqlWalker);
36+
}
37+
38+
public function getReturnType(): Type
39+
{
40+
return Type::getType(Types::INTEGER);
41+
}
42+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions;
6+
7+
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
8+
use Doctrine\ORM\Query\AST\Node;
9+
use Doctrine\ORM\Query\Lexer;
10+
use Doctrine\ORM\Query\Parser;
11+
use Doctrine\ORM\Query\SqlWalker;
12+
13+
/**
14+
* Implementation of PostgreSql FLOOR() function.
15+
*
16+
* @see https://www.postgresql.org/docs/current/functions-math.html#FUNCTIONS-MATH-FUNC-TABLE
17+
*
18+
* @example FLOOR(entity.field)
19+
*/
20+
final class Floor extends FunctionNode
21+
{
22+
private Node $field;
23+
24+
public function parse(Parser $parser): void
25+
{
26+
$parser->match(Lexer::T_IDENTIFIER);
27+
$parser->match(Lexer::T_OPEN_PARENTHESIS);
28+
29+
$this->field = $parser->StringPrimary();
30+
31+
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
32+
}
33+
34+
public function getSql(SqlWalker $sqlWalker): string
35+
{
36+
return "FLOOR({$this->field->dispatch($sqlWalker)})";
37+
}
38+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions;
6+
7+
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
8+
use Doctrine\ORM\Query\Lexer;
9+
use Doctrine\ORM\Query\Parser;
10+
use Doctrine\ORM\Query\SqlWalker;
11+
12+
/**
13+
* Implementation of PostgreSql RANDOM() function.
14+
*
15+
* @see https://www.postgresql.org/docs/current/functions-math.html#FUNCTIONS-MATH-FUNC-TABLE
16+
*
17+
* @example RANDOM()
18+
*/
19+
final class Random extends FunctionNode
20+
{
21+
public function parse(Parser $parser): void
22+
{
23+
$parser->match(Lexer::T_IDENTIFIER);
24+
$parser->match(Lexer::T_OPEN_PARENTHESIS);
25+
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
26+
}
27+
28+
public function getSql(SqlWalker $sqlWalker): string
29+
{
30+
return 'RANDOM()';
31+
}
32+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions;
6+
7+
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
8+
use Doctrine\ORM\Query\AST\Literal;
9+
use Doctrine\ORM\Query\AST\Node;
10+
use Doctrine\ORM\Query\Lexer;
11+
use Doctrine\ORM\Query\Parser;
12+
use Doctrine\ORM\Query\SqlWalker;
13+
14+
/**
15+
* Implementation of PostgreSql ROUND() function.
16+
*
17+
* @see https://www.postgresql.org/docs/current/functions-math.html#FUNCTIONS-MATH-FUNC-TABLE
18+
*
19+
* @example ROUND(entity.field)
20+
* @example ROUND(entity.field, 2)
21+
*/
22+
final class Round extends FunctionNode
23+
{
24+
private Node $field;
25+
private ?Literal $precision = null;
26+
27+
public function parse(Parser $parser): void
28+
{
29+
$parser->match(Lexer::T_IDENTIFIER);
30+
$parser->match(Lexer::T_OPEN_PARENTHESIS);
31+
32+
$this->field = $parser->StringPrimary();
33+
34+
if ($parser->getLexer()->isNextToken(Lexer::T_COMMA)) {
35+
$parser->match(Lexer::T_COMMA);
36+
$this->precision = $parser->Literal();
37+
}
38+
39+
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
40+
}
41+
42+
public function getSql(SqlWalker $sqlWalker): string
43+
{
44+
return \sprintf('ROUND(%s%s)', $this->field->dispatch($sqlWalker), $this->precision !== null ? ", {$this->precision->dispatch($sqlWalker)}" : '');
45+
}
46+
}

0 commit comments

Comments
 (0)