Skip to content

Commit 27fbf42

Browse files
committed
add json basic functions support
1 parent a2df494 commit 27fbf42

File tree

6 files changed

+217
-0
lines changed

6 files changed

+217
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions;
6+
7+
use Doctrine\ORM\Query\Lexer;
8+
use Doctrine\ORM\Query\Parser;
9+
10+
/**
11+
* Implementation of PostgreSql json array field retrieval by index
12+
* @see https://www.postgresql.org/docs/current/functions-json.html
13+
* @example JSON_GET_ARRAY_ELEMENT(entity.field, 1)
14+
*/
15+
final class JsonGetArrayElement extends JsonGetField
16+
{
17+
public function parse(Parser $parser): void
18+
{
19+
$parser->match(Lexer::T_IDENTIFIER);
20+
$parser->match(Lexer::T_OPEN_PARENTHESIS);
21+
22+
$this->field = $parser->StringPrimary();
23+
$parser->match(Lexer::T_COMMA);
24+
$this->path[] = $parser->ArithmeticPrimary();
25+
26+
if (!$parser->getLexer()->isNextToken(Lexer::T_CLOSE_PARENTHESIS)) {
27+
while ($parser->getLexer()->isNextToken(Lexer::T_COMMA)) {
28+
$parser->match(Lexer::T_COMMA);
29+
$this->path[] = $parser->ArithmeticPrimary();
30+
}
31+
}
32+
33+
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
34+
}
35+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions;
6+
7+
use Doctrine\ORM\Query\Lexer;
8+
use Doctrine\ORM\Query\Parser;
9+
10+
/**
11+
* Implementation of PostgreSql json array field retrieval by index
12+
* @see https://www.postgresql.org/docs/current/functions-json.html
13+
* @example JSON_GET_ARRAY_ELEMENT_AS_TEXT(entity.field, 1)
14+
*/
15+
final class JsonGetArrayElementAsText extends JsonGetFieldAsText
16+
{
17+
public function parse(Parser $parser): void
18+
{
19+
$parser->match(Lexer::T_IDENTIFIER);
20+
$parser->match(Lexer::T_OPEN_PARENTHESIS);
21+
22+
$this->field = $parser->StringPrimary();
23+
$parser->match(Lexer::T_COMMA);
24+
$this->path[] = $parser->ArithmeticPrimary();
25+
26+
if (!$parser->getLexer()->isNextToken(Lexer::T_CLOSE_PARENTHESIS)) {
27+
while ($parser->getLexer()->isNextToken(Lexer::T_COMMA)) {
28+
$parser->match(Lexer::T_COMMA);
29+
$this->path[] = $parser->ArithmeticPrimary();
30+
}
31+
}
32+
33+
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
34+
}
35+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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 json object field retrieval by path
15+
* @see https://www.postgresql.org/docs/current/functions-json.html
16+
* @example JSON_GET_FIELD(entity.field, 'a', 'b')
17+
*/
18+
class JsonGetField extends FunctionNode
19+
{
20+
protected Node $field;
21+
22+
/**
23+
* @var Node[]
24+
*/
25+
protected array $path = [];
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+
$parser->match(Lexer::T_COMMA);
34+
$this->path[] = $parser->StringPrimary();
35+
36+
if (!$parser->getLexer()->isNextToken(Lexer::T_CLOSE_PARENTHESIS)) {
37+
while ($parser->getLexer()->isNextToken(Lexer::T_COMMA)) {
38+
$parser->match(Lexer::T_COMMA);
39+
$this->path[] = $parser->StringPrimary();
40+
}
41+
}
42+
43+
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
44+
}
45+
46+
public function getSql(SqlWalker $sqlWalker): string
47+
{
48+
return sprintf(
49+
'%s->%s',
50+
$this->field->dispatch($sqlWalker),
51+
implode(
52+
'->',
53+
array_map(static fn (Node $node) => $node->dispatch($sqlWalker), $this->path)
54+
)
55+
);
56+
}
57+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions;
6+
7+
use Doctrine\ORM\Query\AST\Node;
8+
use Doctrine\ORM\Query\SqlWalker;
9+
10+
/**
11+
* Implementation of PostgreSql json object field as text retrieval by path
12+
* @see https://www.postgresql.org/docs/current/functions-json.html
13+
* @example JSON_GET_FIELD_AS_TEXT(entity.field, 'a', 'b')
14+
*/
15+
class JsonGetFieldAsText extends JsonGetField
16+
{
17+
public function getSql(SqlWalker $sqlWalker): string
18+
{
19+
$path = array_map(static fn (Node $node) => $node->dispatch($sqlWalker), $this->path);
20+
21+
$lastPathElement = array_pop($path);
22+
23+
$sql = $this->field->dispatch($sqlWalker);
24+
25+
if (count($path) > 0) {
26+
$sql .= sprintf('->%s', implode('->', $path));
27+
}
28+
29+
return "$sql->>$lastPathElement";
30+
}
31+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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 json object retrieval by path
15+
* @see https://www.postgresql.org/docs/current/functions-json.html
16+
* @example JSON_GET_OBJECT(entity.field, '{a,b}')
17+
*/
18+
class JsonGetObject extends FunctionNode
19+
{
20+
protected Node $field;
21+
22+
protected Node $path;
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+
$parser->match(Lexer::T_COMMA);
31+
$this->path = $parser->StringPrimary();
32+
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
33+
}
34+
35+
public function getSql(SqlWalker $sqlWalker): string
36+
{
37+
return "{$this->field->dispatch($sqlWalker)} #> {$this->path->dispatch($sqlWalker)}";
38+
}
39+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions;
6+
7+
use Doctrine\ORM\Query\SqlWalker;
8+
9+
/**
10+
* Implementation of PostgreSql json object as text retrieval by path
11+
* @see https://www.postgresql.org/docs/current/functions-json.html
12+
* @example JSON_GET_OBJECT_AS_TEXT(entity.field, '{a,b}')
13+
*/
14+
final class JsonGetObjectAsText extends JsonGetObject
15+
{
16+
public function getSql(SqlWalker $sqlWalker): string
17+
{
18+
return "{$this->field->dispatch($sqlWalker)} #>> {$this->path->dispatch($sqlWalker)}";
19+
}
20+
}

0 commit comments

Comments
 (0)