Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;

/**
* Implementation of PostgreSQL REGEXP_LIKE() with flags.
* @deprecated This function will be dropped in v4.0. Use RegexpLike instead.
*
* Implementation of PostgreSQL REGEXP_LIKE() with flags.
* @see https://www.postgresql.org/docs/15/functions-matching.html#FUNCTIONS-POSIX-REGEXP
* @see https://www.postgresql.org/docs/15/functions-matching.html#POSIX-EMBEDDED-OPTIONS-TABLE
* @since 2.0
Expand All @@ -17,7 +18,7 @@ class FlaggedRegexpLike extends BaseFunction
{
protected function customizeFunction(): void
{
$this->setFunctionPrototype('regexp_like(%s, %s, 1, %s)');
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was actually a bug that never worked as intended.

$this->setFunctionPrototype('regexp_like(%s, %s, %s)');
$this->addNodeMapping('StringPrimary');
$this->addNodeMapping('StringPrimary');
$this->addNodeMapping('StringPrimary');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;

/**
* Implementation of PostgreSQL REGEXP_MATCH() with flags.
* @deprecated This function will be dropped in v4.0. Use RegexpMatch instead.
*
* Implementation of PostgreSQL REGEXP_MATCH() with flags.
* @see https://www.postgresql.org/docs/15/functions-matching.html#FUNCTIONS-POSIX-REGEXP
* @see https://www.postgresql.org/docs/15/functions-matching.html#POSIX-EMBEDDED-OPTIONS-TABLE
* @since 2.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
namespace MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;

/**
* Implementation of PostgreSQL REGEXP_REPLACE().
* @deprecated This function will be dropped in v4.0. Use RegexpReplace instead.
*
* Implementation of PostgreSQL REGEXP_REPLACE().
* @see https://www.postgresql.org/docs/15/functions-matching.html#FUNCTIONS-POSIX-REGEXP
* @since 2.5
*
Expand Down
22 changes: 19 additions & 3 deletions src/MartinGeorgiev/Doctrine/ORM/Query/AST/Functions/RegexpLike.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,36 @@
/**
* Implementation of PostgreSQL REGEXP_LIKE().
*
* @see https://www.postgresql.org/docs/15/functions-matching.html#FUNCTIONS-POSIX-REGEXP
* Returns true if a string matches a POSIX regular expression pattern, or false if it does not.
*
* @see https://www.postgresql.org/docs/17/functions-matching.html#FUNCTIONS-POSIX-REGEXP
* @since 2.0
*
* @author Martin Georgiev <martin.georgiev@gmail.com>
*
* @example Using it in DQL: "SELECT REGEXP_LIKE(e.text, 'pattern', 'i') FROM Entity e"
*/
class RegexpLike extends BaseRegexpFunction
class RegexpLike extends BaseVariadicFunction
{
protected function getNodeMappingPattern(): array
{
return [
'StringPrimary',
];
}

protected function getFunctionName(): string
{
return 'regexp_like';
}

protected function getParameterCount(): int
protected function getMinArgumentCount(): int
{
return 2;
}

protected function getMaxArgumentCount(): int
{
return 3;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,36 @@
/**
* Implementation of PostgreSQL REGEXP_MATCH().
*
* @see https://www.postgresql.org/docs/15/functions-matching.html#FUNCTIONS-POSIX-REGEXP
* Returns the first substring(s) that match a POSIX regular expression pattern, or NULL if there is no match.
*
* @see https://www.postgresql.org/docs/17/functions-matching.html#FUNCTIONS-POSIX-REGEXP
* @since 2.0
*
* @author Martin Georgiev <martin.georgiev@gmail.com>
*
* @example Using it in DQL: "SELECT REGEXP_MATCH(e.text, 'pattern', 'i') FROM Entity e"
*/
class RegexpMatch extends BaseRegexpFunction
class RegexpMatch extends BaseVariadicFunction
{
protected function getNodeMappingPattern(): array
{
return [
'StringPrimary',
];
}

protected function getFunctionName(): string
{
return 'regexp_match';
}

protected function getParameterCount(): int
protected function getMinArgumentCount(): int
{
return 2;
}

protected function getMaxArgumentCount(): int
{
return 3;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,25 @@
* @since 2.5
*
* @author Colin Doig
* @author Martin Georgiev <martin.georgiev@gmail.com>
*
* @example Using it in DQL: "SELECT REGEXP_REPLACE(e.text, 'pattern', 'replacement', 3, 2, 'i') FROM Entity e"
*/
class RegexpReplace extends BaseVariadicFunction
{
protected function getNodeMappingPattern(): array
{
/*
* PostgreSQL overloads the 4th argument depending on its type:
* - if the 4th arg is a string, it’s taken as flags.
* - if the 4th arg is an integer, it’s taken as start position. This can be extended with the Nth argument.
*/
return [
'StringPrimary,StringPrimary,StringPrimary,ArithmeticPrimary,ArithmeticPrimary,StringPrimary',
'StringPrimary,StringPrimary,StringPrimary,ArithmeticPrimary,ArithmeticPrimary',
'StringPrimary,StringPrimary,StringPrimary,ArithmeticPrimary,StringPrimary',
'StringPrimary,StringPrimary,StringPrimary,ArithmeticPrimary',
'StringPrimary,StringPrimary,StringPrimary,StringPrimary',
'StringPrimary,StringPrimary,StringPrimary',
'StringPrimary,StringPrimary,StringPrimary,ArithmeticPrimary,ArithmeticPrimary,StringPrimary', // with start, N and flags: regexp_replace(string, pattern, replacement, 3, 2, 'i')
'StringPrimary,StringPrimary,StringPrimary,ArithmeticPrimary,ArithmeticPrimary', // with start and N: regexp_replace(string, pattern, replacement, 3, 2)
'StringPrimary,StringPrimary,StringPrimary,ArithmeticPrimary', // with start: regexp_replace(string, pattern, replacement, 3)
'StringPrimary,StringPrimary,StringPrimary,StringPrimary', // with flags: regexp_replace(string, pattern, replacement, 'i')
'StringPrimary,StringPrimary,StringPrimary', // basic replacement: regexp_replace(string, pattern, replacement)
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public function throws_an_exception_when_lexer_is_not_populated_with_a_lookahead
->willReturn(new Configuration());

$query = new Query($em);
$query->setDQL('TRUE');
$query->setDQL('SELECT 1');

$parser = new Parser($query);
$parser->getLexer()->moveNext();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ class FlaggedRegexpLikeTest extends TestCase
protected function getStringFunctions(): array
{
return [
'FLAGGED_REGEXP_LIKE' => FlaggedRegexpLike::class,
'FLAGGED_REGEXP_LIKE' => FlaggedRegexpLike::class, // @phpstan-ignore-line
];
}

protected function getExpectedSqlStatements(): array
{
return [
"SELECT regexp_like(c0_.text1, 'pattern', 1, 'i') AS sclr_0 FROM ContainsTexts c0_",
"SELECT regexp_like(c0_.text1, 'pattern', 'i') AS sclr_0 FROM ContainsTexts c0_",
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class FlaggedRegexpMatchTest extends TestCase
protected function getStringFunctions(): array
{
return [
'FLAGGED_REGEXP_MATCH' => FlaggedRegexpMatch::class,
'FLAGGED_REGEXP_MATCH' => FlaggedRegexpMatch::class, // @phpstan-ignore-line
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class FlaggedRegexpReplaceTest extends TestCase
protected function getStringFunctions(): array
{
return [
'FLAGGED_REGEXP_REPLACE' => FlaggedRegexpReplace::class,
'FLAGGED_REGEXP_REPLACE' => FlaggedRegexpReplace::class, // @phpstan-ignore-line
];
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,17 @@
namespace Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;

use Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsTexts;
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\BaseVariadicFunction;
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException;
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\RegexpLike;

class RegexpLikeTest extends TestCase
class RegexpLikeTest extends BaseVariadicFunctionTestCase
{
protected function createFixture(): BaseVariadicFunction
{
return new RegexpLike('REGEXP_LIKE');
}

protected function getStringFunctions(): array
{
return [
Expand All @@ -19,14 +26,34 @@ protected function getStringFunctions(): array
protected function getExpectedSqlStatements(): array
{
return [
"SELECT regexp_like(c0_.text1, 'pattern') AS sclr_0 FROM ContainsTexts c0_",
'basic match' => "SELECT regexp_like(c0_.text1, 'pattern') AS sclr_0 FROM ContainsTexts c0_",
'with flags' => "SELECT regexp_like(c0_.text1, 'pattern', 'i') AS sclr_0 FROM ContainsTexts c0_",
];
}

protected function getDqlStatements(): array
{
return [
\sprintf("SELECT REGEXP_LIKE(e.text1, 'pattern') FROM %s e", ContainsTexts::class),
'basic match' => \sprintf("SELECT REGEXP_LIKE(e.text1, 'pattern') FROM %s e", ContainsTexts::class),
'with flags' => \sprintf("SELECT REGEXP_LIKE(e.text1, 'pattern', 'i') FROM %s e", ContainsTexts::class),
];
}

public function test_too_few_arguments_throws_exception(): void
{
$this->expectException(InvalidArgumentForVariadicFunctionException::class);
$this->expectExceptionMessage('regexp_like() requires at least 2 arguments');

$dql = \sprintf('SELECT REGEXP_LIKE(e.text1) FROM %s e', ContainsTexts::class);
$this->buildEntityManager()->createQuery($dql)->getSQL();
}

public function test_too_many_arguments_throws_exception(): void
{
$this->expectException(InvalidArgumentForVariadicFunctionException::class);
$this->expectExceptionMessage('regexp_like() requires between 2 and 3 arguments');

$dql = \sprintf("SELECT REGEXP_LIKE(e.text1, 'pattern', 'i', 'extra_arg') FROM %s e", ContainsTexts::class);
$this->buildEntityManager()->createQuery($dql)->getSQL();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,17 @@
namespace Tests\MartinGeorgiev\Doctrine\ORM\Query\AST\Functions;

use Fixtures\MartinGeorgiev\Doctrine\Entity\ContainsTexts;
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\BaseVariadicFunction;
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Exception\InvalidArgumentForVariadicFunctionException;
use MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\RegexpMatch;

class RegexpMatchTest extends TestCase
class RegexpMatchTest extends BaseVariadicFunctionTestCase
{
protected function createFixture(): BaseVariadicFunction
{
return new RegexpMatch('REGEXP_MATCH');
}

protected function getStringFunctions(): array
{
return [
Expand All @@ -19,14 +26,34 @@ protected function getStringFunctions(): array
protected function getExpectedSqlStatements(): array
{
return [
"SELECT regexp_match(c0_.text1, 'pattern') AS sclr_0 FROM ContainsTexts c0_",
'basic match' => "SELECT regexp_match(c0_.text1, 'pattern') AS sclr_0 FROM ContainsTexts c0_",
'with flags' => "SELECT regexp_match(c0_.text1, 'pattern', 'i') AS sclr_0 FROM ContainsTexts c0_",
];
}

protected function getDqlStatements(): array
{
return [
\sprintf("SELECT REGEXP_MATCH(e.text1, 'pattern') FROM %s e", ContainsTexts::class),
'basic match' => \sprintf("SELECT REGEXP_MATCH(e.text1, 'pattern') FROM %s e", ContainsTexts::class),
'with flags' => \sprintf("SELECT REGEXP_MATCH(e.text1, 'pattern', 'i') FROM %s e", ContainsTexts::class),
];
}

public function test_too_few_arguments_throws_exception(): void
{
$this->expectException(InvalidArgumentForVariadicFunctionException::class);
$this->expectExceptionMessage('regexp_match() requires at least 2 arguments');

$dql = \sprintf('SELECT REGEXP_MATCH(e.text1) FROM %s e', ContainsTexts::class);
$this->buildEntityManager()->createQuery($dql)->getSQL();
}

public function test_too_many_arguments_throws_exception(): void
{
$this->expectException(InvalidArgumentForVariadicFunctionException::class);
$this->expectExceptionMessage('regexp_match() requires between 2 and 3 arguments');

$dql = \sprintf("SELECT REGEXP_MATCH(e.text1, 'pattern', 'i', 'extra_arg') FROM %s e", ContainsTexts::class);
$this->buildEntityManager()->createQuery($dql)->getSQL();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ protected function getExpectedSqlStatements(): array
'basic replacement' => "SELECT regexp_replace(c0_.text1, 'pattern', 'replacement') AS sclr_0 FROM ContainsTexts c0_",
'with flags but no start position' => "SELECT regexp_replace(c0_.text1, 'pattern', 'replacement', 'i') AS sclr_0 FROM ContainsTexts c0_",
'with start position' => "SELECT regexp_replace(c0_.text1, 'pattern', 'replacement', 3) AS sclr_0 FROM ContainsTexts c0_",
'with start position and flags' => "SELECT regexp_replace(c0_.text1, 'pattern', 'replacement', 3, 'i') AS sclr_0 FROM ContainsTexts c0_",
'with occurrence count but no flags' => "SELECT regexp_replace(c0_.text1, 'pattern', 'replacement', 3, 2) AS sclr_0 FROM ContainsTexts c0_",
'with occurrence count and flags' => "SELECT regexp_replace(c0_.text1, 'pattern', 'replacement', 3, 2, 'i') AS sclr_0 FROM ContainsTexts c0_",
];
Expand All @@ -41,7 +40,6 @@ protected function getDqlStatements(): array
'basic replacement' => \sprintf("SELECT REGEXP_REPLACE(e.text1, 'pattern', 'replacement') FROM %s e", ContainsTexts::class),
'with flags but no start position' => \sprintf("SELECT REGEXP_REPLACE(e.text1, 'pattern', 'replacement', 'i') FROM %s e", ContainsTexts::class),
'with start position' => \sprintf("SELECT REGEXP_REPLACE(e.text1, 'pattern', 'replacement', 3) FROM %s e", ContainsTexts::class),
'with start position and flags' => \sprintf("SELECT REGEXP_REPLACE(e.text1, 'pattern', 'replacement', 3, 'i') FROM %s e", ContainsTexts::class),
'with occurrence count but no flags' => \sprintf("SELECT REGEXP_REPLACE(e.text1, 'pattern', 'replacement', 3, 2) FROM %s e", ContainsTexts::class),
'with occurrence count and flags' => \sprintf("SELECT REGEXP_REPLACE(e.text1, 'pattern', 'replacement', 3, 2, 'i') FROM %s e", ContainsTexts::class),
];
Expand Down
Loading