Skip to content

Commit

Permalink
Merge pull request #7 from pfilsx/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
pfilsx authored Mar 19, 2023
2 parents 2f98dc8 + 5b3b45e commit 861578c
Show file tree
Hide file tree
Showing 34 changed files with 500 additions and 57 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Features
* [Trait](src/ORM/Trait/ExistsMethodRepositoryTrait.php) for easy use of [SELECT EXISTS(...)](https://www.postgresql.org/docs/current/functions-subquery.html#FUNCTIONS-SUBQUERY-EXISTS) in your entity repositories
* Aggregate functions with filter condition support
* Array types
* [Text Search](https://www.postgresql.org/docs/current/textsearch.html) support

Requirement
-----------
Expand Down
75 changes: 68 additions & 7 deletions docs/Functions-and-Operators.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
Available functions
===================

| PostgreSQL function | DQL function | Implementation |
|---------------------|--------------|-------------------------------------------------------------------------------------------------------------|
| ARRAY_AGG() | ARRAY_AGG | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\ArrayAgg](../src/ORM/Query/AST/Functions/ArrayAgg.php) |
| JSON_AGG() | JSON_AGG | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonAgg](../src/ORM/Query/AST/Functions/JsonAgg.php) |
| JSONB_AGG() | JSONB_AGG | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonbAgg](../src/ORM/Query/AST/Functions/JsonbAgg.php) |
| STRING_AGG() | STRING_AGG | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\StringAgg](../src/ORM/Query/AST/Functions/StringAgg.php) |
| PostgreSQL function | DQL function | Implementation |
|------------------------|----------------------|-------------------------------------------------------------------------------------------------------------------------------|
| ARRAY_AGG() | ARRAY_AGG | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\ArrayAgg](../src/ORM/Query/AST/Functions/ArrayAgg.php) |
| JSON_AGG() | JSON_AGG | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonAgg](../src/ORM/Query/AST/Functions/JsonAgg.php) |
| JSONB_AGG() | JSONB_AGG | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonbAgg](../src/ORM/Query/AST/Functions/JsonbAgg.php) |
| PHRASETO_TSQUERY() | PHRASETO_TSQUERY | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\PhraseToTsQuery](../src/ORM/Query/AST/Functions/PhraseToTsQuery.php) |
| PLAINTO_TSQUERY() | PLAINTO_TSQUERY | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\PlainToTsQuery](../src/ORM/Query/AST/Functions/PlainToTsQuery.php) |
| STRING_AGG() | STRING_AGG | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\StringAgg](../src/ORM/Query/AST/Functions/StringAgg.php) |
| TO_TSQUERY() | TO_TSQUERY | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\ToTsQuery](../src/ORM/Query/AST/Functions/ToTsQuery.php) |
| TO_TSVECTOR() | TO_TSVECTOR | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\ToTsVector](../src/ORM/Query/AST/Functions/ToTsVector.php) |
| TS_HEADLINE() | TS_HEADLINE | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\TsHeadline](../src/ORM/Query/AST/Functions/TsHeadline.php) |
| TS_RANK() | TS_RANK | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\TsRank](../src/ORM/Query/AST/Functions/TsRank.php) |
| TS_RANK_CD() | TS_RANK_CD | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\TsRankCd](../src/ORM/Query/AST/Functions/TsRankCd.php) |
| WEBSEARCH_TO_TSQUERY() | WEBSEARCH_TO_TSQUERY | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\WebsearchToTsQuery](../src/ORM/Query/AST/Functions/WebsearchToTsQuery.php) |

Available operators
===================
Expand All @@ -20,4 +28,57 @@ Available operators
| -> | JSON_GET_FIELD | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonGetField](../src/ORM/Query/AST/Functions/JsonGetField.php) |
| ->> | JSON_GET_FIELD_AS_TEXT | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonGetFieldAsText](../src/ORM/Query/AST/Functions/JsonGetFieldAsText.php) |
| #> | JSON_GET_OBJECT | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonGetObject](../src/ORM/Query/AST/Functions/JsonGetObject.php) |
| #>> | JSON_GET_OBJECT_AS_TEXT | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonGetObjectAsText](../src/ORM/Query/AST/Functions/JsonGetObjectAsText.php) |
| #>> | JSON_GET_OBJECT_AS_TEXT | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonGetObjectAsText](../src/ORM/Query/AST/Functions/JsonGetObjectAsText.php) |
| @@ | TS_MATCH | [Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\TsMatch](../src/ORM/Query/AST/Functions/TsMatch.php) |

Integration with Doctrine
=========================

```php
<?php

use Doctrine\ORM\Configuration;
use Doctrine\ORM\EntityManager;

$configuration = new Configuration();

$configuration->addCustomStringFunction('ARRAY_AGG', Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\ArrayAgg::class);
$configuration->addCustomStringFunction('JSONB_CONCAT', Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonbConcat::class);
$configuration->addCustomStringFunction('JSON_GET_FIELD', Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonGetField::class);
$configuration->addCustomStringFunction('TO_TSVECTOR', Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\ToTsVector::class);
$configuration->addCustomNumericFunction('TS_RANK', Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\TsRank::class);
$configuration->addCustomNumericFunction('TS_MATCH', Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\TsMatch::class);

// ...

$em = EntityManager::create($connection, $configuration);
```

Integration with Symfony
=========================

```yaml
# config/packages/doctrine.yaml
doctrine:
orm:
dql:
string_functions:
array_agg: Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\ArrayAgg
jsonb_concat: Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonbConcat
json_get_field: Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonGetField
to_tsvector: Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\ToTsVector
ts_match: Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\TsMatch
numeric_functions:
ts_rank: Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\TsRank
# or only for specific em
entity_managers:
em_name:
string_functions:
array_agg: Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\ArrayAgg
jsonb_concat: Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonbConcat
json_get_field: Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\JsonGetField
to_tsvector: Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\ToTsVector
ts_match: Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\TsMatch
numeric_functions:
ts_rank: Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions\TsRank
```
59 changes: 33 additions & 26 deletions docs/Types.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
Available types
===============

| PostgreSQL type | Register as | Implementation |
|-----------------|-------------|-----------------------------------------------------------------------------------------|
| _bool | bool[] | [Pfilsx\PostgreSQLDoctrine\DBAL\Type\BooleanArray](../src/DBAL/Type/BooleanArray.php) |
| _int2 | smallint[] | [Pfilsx\PostgreSQLDoctrine\DBAL\Type\SmallIntArray](../src/DBAL/Type/SmallIntArray.php) |
| _int4 | integer[] | [Pfilsx\PostgreSQLDoctrine\DBAL\Type\IntegerArray](../src/DBAL/Type/IntegerArray.php) |
| _int8 | bigint[] | [Pfilsx\PostgreSQLDoctrine\DBAL\Type\BigIntArray](../src/DBAL/Type/BigIntArray.php) |
| _text | text[] | [Pfilsx\PostgreSQLDoctrine\DBAL\Type\TextArray](../src/DBAL/Type/TextArray.php) |
| PostgreSQL type | Register as | Implementation |
|-----------------|-------------|-------------------------------------------------------------------------------------------------|
| _bool | bool[] | [Pfilsx\PostgreSQLDoctrine\DBAL\Type\BooleanArrayType](../src/DBAL/Type/BooleanArrayType.php) |
| _int2 | smallint[] | [Pfilsx\PostgreSQLDoctrine\DBAL\Type\SmallIntArrayType](../src/DBAL/Type/SmallIntArrayType.php) |
| _int4 | integer[] | [Pfilsx\PostgreSQLDoctrine\DBAL\Type\IntegerArrayType](../src/DBAL/Type/IntegerArrayType.php) |
| _int8 | bigint[] | [Pfilsx\PostgreSQLDoctrine\DBAL\Type\BigIntArrayType](../src/DBAL/Type/BigIntArrayType.php) |
| _text | text[] | [Pfilsx\PostgreSQLDoctrine\DBAL\Type\TextArrayType](../src/DBAL/Type/TextArrayType.php) |
| tsvector | tsvector | [Pfilsx\PostgreSQLDoctrine\DBAL\Type\TsVectorType](../src/DBAL/Type/TsVectorType.php) |

Integration with Doctrine
=========================
Expand All @@ -17,37 +18,41 @@ Integration with Doctrine

use Doctrine\DBAL\Types\Type;

Type::addType('bool[]', 'Pfilsx\PostgreSQLDoctrine\DBAL\Type\BooleanArray');
Type::addType('smallint[]', 'Pfilsx\PostgreSQLDoctrine\DBAL\Type\SmallIntArray');
Type::addType('integer[]', 'Pfilsx\PostgreSQLDoctrine\DBAL\Type\IntegerArray');
Type::addType('bigint[]', 'Pfilsx\PostgreSQLDoctrine\DBAL\Type\BigIntArray');
Type::addType('text[]', 'Pfilsx\PostgreSQLDoctrine\DBAL\Type\TextArray');
Type::addType('bool[]', 'Pfilsx\PostgreSQLDoctrine\DBAL\Type\BooleanArrayType');
Type::addType('smallint[]', 'Pfilsx\PostgreSQLDoctrine\DBAL\Type\SmallIntArrayType');
Type::addType('integer[]', 'Pfilsx\PostgreSQLDoctrine\DBAL\Type\IntegerArrayType');
Type::addType('bigint[]', 'Pfilsx\PostgreSQLDoctrine\DBAL\Type\BigIntArrayType');
Type::addType('text[]', 'Pfilsx\PostgreSQLDoctrine\DBAL\Type\TextArrayType');
Type::addType('tsvector', 'Pfilsx\PostgreSQLDoctrine\DBAL\Type\TsVectorType');

// ...

$platform = $em->getConnection()->getDatabasePlatform();
$platform->registerDoctrineTypeMapping('bool[]','bool[]');
$platform->registerDoctrineTypeMapping('_bool','bool[]');
$platform->registerDoctrineTypeMapping('integer[]','integer[]');
$platform->registerDoctrineTypeMapping('_int4','integer[]');
$platform->registerDoctrineTypeMapping('bigint[]','bigint[]');
$platform->registerDoctrineTypeMapping('_int8','bigint[]');
$platform->registerDoctrineTypeMapping('text[]','text[]');
$platform->registerDoctrineTypeMapping('_text','text[]');
$platform->registerDoctrineTypeMapping('bool[]', 'bool[]');
$platform->registerDoctrineTypeMapping('_bool', 'bool[]');
$platform->registerDoctrineTypeMapping('integer[]', 'integer[]');
$platform->registerDoctrineTypeMapping('_int4', 'integer[]');
$platform->registerDoctrineTypeMapping('bigint[]', 'bigint[]');
$platform->registerDoctrineTypeMapping('_int8', 'bigint[]');
$platform->registerDoctrineTypeMapping('text[]', 'text[]');
$platform->registerDoctrineTypeMapping('_text', 'text[]');
$platform->registerDoctrineTypeMapping('tsvector', 'tsvector');
```

Integration with Symfony
=========================

```yaml
# config/packages/doctrine.yaml
doctrine:
dbal:
types:
bool[]: Pfilsx\PostgreSQLDoctrine\DBAL\Type\BooleanArray
smallint[]: Pfilsx\PostgreSQLDoctrine\DBAL\Type\SmallIntArray
integer[]: Pfilsx\PostgreSQLDoctrine\DBAL\Type\IntegerArray
bigint[]: Pfilsx\PostgreSQLDoctrine\DBAL\Type\BigIntArray
text[]: Pfilsx\PostgreSQLDoctrine\DBAL\Type\TextArray
bool[]: Pfilsx\PostgreSQLDoctrine\DBAL\Type\BooleanArrayType
smallint[]: Pfilsx\PostgreSQLDoctrine\DBAL\Type\SmallIntArrayType
integer[]: Pfilsx\PostgreSQLDoctrine\DBAL\Type\IntegerArrayType
bigint[]: Pfilsx\PostgreSQLDoctrine\DBAL\Type\BigIntArrayType
text[]: Pfilsx\PostgreSQLDoctrine\DBAL\Type\TextArrayType
tsvector: Pfilsx\PostgreSQLDoctrine\DBAL\Type\TsVectorType

mapping_types:
bool[]: bool[]
Expand All @@ -60,7 +65,8 @@ doctrine:
_int8: bigint[]
text[]: text[]
_text: text[]
# or
tsvector: tsvector
# or only for specific connection
connections:
connection_name:
mapping_types:
Expand All @@ -74,4 +80,5 @@ doctrine:
_int8: bigint[]
text[]: text[]
_text: text[]
tsvector: tsvector
```
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*
* @see https://www.postgresql.org/docs/current/arrays.html
*/
class BigIntArray extends AbstractArrayType
class BigIntArrayType extends AbstractArrayType
{
protected static function getArrayType(): ArrayTypeEnum
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*
* @see https://www.postgresql.org/docs/current/arrays.html
*/
class BooleanArray extends AbstractArrayType
class BooleanArrayType extends AbstractArrayType
{
protected static function getArrayType(): ArrayTypeEnum
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*
* @see https://www.postgresql.org/docs/current/arrays.html
*/
class IntegerArray extends AbstractArrayType
class IntegerArrayType extends AbstractArrayType
{
protected static function getArrayType(): ArrayTypeEnum
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*
* @see https://www.postgresql.org/docs/current/arrays.html
*/
class SmallIntArray extends AbstractArrayType
class SmallIntArrayType extends AbstractArrayType
{
protected static function getArrayType(): ArrayTypeEnum
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*
* @see https://www.postgresql.org/docs/current/arrays.html
*/
class TextArray extends AbstractArrayType
class TextArrayType extends AbstractArrayType
{
protected static function getArrayType(): ArrayTypeEnum
{
Expand Down
32 changes: 32 additions & 0 deletions src/DBAL/Type/TsVectorType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace Pfilsx\PostgreSQLDoctrine\DBAL\Type;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type;

/**
* Implementation of PostgreSql TSVECTOR data type.
*
* @see https://www.postgresql.org/docs/current/datatype-textsearch.html#DATATYPE-TSVECTOR
*/
class TsVectorType extends Type
{
/**
* @param array<string, mixed> $column
* @param AbstractPlatform $platform
*
* @return string
*/
public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
{
return 'TSVECTOR';
}

public function getName(): string
{
return 'tsvector';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use Doctrine\ORM\Query\SqlWalker;
use Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\FilterExpression;

abstract class AggregateWithFilterFunction extends FunctionNode
abstract class AbstractAggregateWithFilterFunction extends FunctionNode
{
private const FILTER_IDENTIFIER = 'FILTER';
private ?FilterExpression $filterExpression = null;
Expand Down
49 changes: 49 additions & 0 deletions src/ORM/Query/AST/Functions/AbstractToTsFunction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace Pfilsx\PostgreSQLDoctrine\ORM\Query\AST\Functions;

use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;

abstract class AbstractToTsFunction extends FunctionNode
{
private Node $document;

private ?Node $config = null;

abstract protected function getFunctionName(): string;

public function parse(Parser $parser): void
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);

$firstNode = $parser->StringPrimary();

$lexer = $parser->getLexer();

if ($lexer->isNextToken(Lexer::T_COMMA)) {
$parser->match(Lexer::T_COMMA);
$this->config = $firstNode;
$this->document = $parser->StringPrimary();
} else {
$this->document = $firstNode;
}

$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}

public function getSql(SqlWalker $sqlWalker): string
{
return sprintf('%s(%s%s)',
$this->getFunctionName(),
$this->config !== null ? $this->config->dispatch($sqlWalker) . ', ' : '',
$this->document->dispatch($sqlWalker)
);
}
}
4 changes: 2 additions & 2 deletions src/ORM/Query/AST/Functions/ArrayAgg.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use Doctrine\ORM\Query\SqlWalker;

/**
* Implementation of PostgreSql ARRAY_AGG().
* Implementation of PostgreSql ARRAY_AGG() function.
*
* @see https://www.postgresql.org/docs/current/functions-aggregate.html#FUNCTIONS-AGGREGATE-TABLE
*
Expand All @@ -19,7 +19,7 @@
* @example ARRAY_AGG(entity.field) FILTER (WHERE entity.field IS NOT NULL)
* @example ARRAY_AGG(DISTINCT entity.field) FILTER (WHERE entity.field IS NOT NULL)
*/
final class ArrayAgg extends AggregateWithFilterFunction
final class ArrayAgg extends AbstractAggregateWithFilterFunction
{
private bool $distinct = false;

Expand Down
4 changes: 2 additions & 2 deletions src/ORM/Query/AST/Functions/JsonAgg.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use Doctrine\ORM\Query\SqlWalker;

/**
* Implementation of PostgreSql JSON_AGG().
* Implementation of PostgreSql JSON_AGG() function.
*
* @see https://www.postgresql.org/docs/current/functions-aggregate.html#FUNCTIONS-AGGREGATE-TABLE
*
Expand All @@ -19,7 +19,7 @@
* @example JSON_AGG(entity.field) FILTER (WHERE entity.field IS NOT NULL)
* @example JSON_AGG(DISTINCT entity.field) FILTER (WHERE entity.field IS NOT NULL)
*/
final class JsonAgg extends AggregateWithFilterFunction
final class JsonAgg extends AbstractAggregateWithFilterFunction
{
private bool $distinct = false;

Expand Down
2 changes: 1 addition & 1 deletion src/ORM/Query/AST/Functions/JsonGetArrayElement.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use Doctrine\ORM\Query\Parser;

/**
* Implementation of PostgreSql json array field retrieval by index.
* Implementation of PostgreSql JSON(B) array field retrieval by index.
*
* @see https://www.postgresql.org/docs/current/functions-json.html
*
Expand Down
2 changes: 1 addition & 1 deletion src/ORM/Query/AST/Functions/JsonGetArrayElementAsText.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use Doctrine\ORM\Query\Parser;

/**
* Implementation of PostgreSql json array field retrieval by index.
* Implementation of PostgreSql JSON(B) array field retrieval by index.
*
* @see https://www.postgresql.org/docs/current/functions-json.html
*
Expand Down
2 changes: 1 addition & 1 deletion src/ORM/Query/AST/Functions/JsonGetField.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use Doctrine\ORM\Query\SqlWalker;

/**
* Implementation of PostgreSql json object field retrieval by path.
* Implementation of PostgreSql JSON(B) object field retrieval by path.
*
* @see https://www.postgresql.org/docs/current/functions-json.html
*
Expand Down
Loading

0 comments on commit 861578c

Please sign in to comment.