Skip to content

Commit 53a71be

Browse files
MrMitchstevelacey
andauthored
Add JSON_LENGTH for MySQL (#356)
Co-authored-by: Steve Lacey <[email protected]>
1 parent 9dd31e4 commit 53a71be

File tree

4 files changed

+78
-1
lines changed

4 files changed

+78
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ MySQL, Oracle, PostgreSQL and SQLite.
1313

1414
| DB | Functions |
1515
|:--:|:---------:|
16-
| MySQL | `ACOS, ADDTIME, AES_DECRYPT, AES_ENCRYPT, ANY_VALUE, ASCII, ASIN, ATAN, ATAN2, BINARY, BIT_COUNT, BIT_XOR, CAST, CEIL, CHAR_LENGTH, COLLATE, CONCAT_WS, CONVERT_TZ, COS, COT, COUNTIF, CRC32, DATE, DATE_FORMAT, DATEADD, DATEDIFF, DATESUB, DAY, DAYNAME, DAYOFWEEK, DAYOFYEAR, DEGREES, DIV, EXP, EXTRACT, FIELD, FIND_IN_SET, FLOOR, FORMAT, FROM_BASE64, FROM_UNIXTIME, GREATEST, GROUP_CONCAT, HEX, HOUR, IFELSE, IFNULL, INET_ATON, INET_NTOA, INET6_ATON, INET6_NTOA, INSTR, IS_IPV4, IS_IPV4_COMPAT, IS_IPV4_MAPPED, IS_IPV6, JSON_CONTAINS, JSON_DEPTH, LAG, LAST_DAY, LEAD, LEAST, LOG, LOG10, LOG2, LPAD, MAKEDATE, MATCH, MD5, MINUTE, MONTH, MONTHNAME, NOW, NULLIF, OVER, PERIOD_DIFF, PI, POWER, QUARTER, RADIANS, RAND, REGEXP, REPLACE, ROUND, RPAD, SECOND, SECTOTIME, SHA1, SHA2, SIN, SOUNDEX, STD, STDDEV, STRTODATE, STR_TO_DATE, SUBSTRING_INDEX, TAN, TIME, TIMEDIFF, TIMESTAMPADD, TIMESTAMPDIFF, TIMETOSEC, TRUNCATE, UNHEX, UNIX_TIMESTAMP, UTC_TIMESTAMP, UUID_SHORT, VARIANCE, WEEK, WEEKDAY, YEAR, YEARMONTH, YEARWEEK` |
16+
| MySQL | `ACOS, ADDTIME, AES_DECRYPT, AES_ENCRYPT, ANY_VALUE, ASCII, ASIN, ATAN, ATAN2, BINARY, BIT_COUNT, BIT_XOR, CAST, CEIL, CHAR_LENGTH, COLLATE, CONCAT_WS, CONVERT_TZ, COS, COT, COUNTIF, CRC32, DATE, DATE_FORMAT, DATEADD, DATEDIFF, DATESUB, DAY, DAYNAME, DAYOFWEEK, DAYOFYEAR, DEGREES, DIV, EXP, EXTRACT, FIELD, FIND_IN_SET, FLOOR, FORMAT, FROM_BASE64, FROM_UNIXTIME, GREATEST, GROUP_CONCAT, HEX, HOUR, IFELSE, IFNULL, INET_ATON, INET_NTOA, INET6_ATON, INET6_NTOA, INSTR, IS_IPV4, IS_IPV4_COMPAT, IS_IPV4_MAPPED, IS_IPV6, JSON_CONTAINS, JSON_DEPTH, JSON_LENGTH, LAG, LAST_DAY, LEAD, LEAST, LOG, LOG10, LOG2, LPAD, MAKEDATE, MATCH, MD5, MINUTE, MONTH, MONTHNAME, NOW, NULLIF, OVER, PERIOD_DIFF, PI, POWER, QUARTER, RADIANS, RAND, REGEXP, REPLACE, ROUND, RPAD, SECOND, SECTOTIME, SHA1, SHA2, SIN, SOUNDEX, STD, STDDEV, STRTODATE, STR_TO_DATE, SUBSTRING_INDEX, TAN, TIME, TIMEDIFF, TIMESTAMPADD, TIMESTAMPDIFF, TIMETOSEC, TRUNCATE, UNHEX, UNIX_TIMESTAMP, UTC_TIMESTAMP, UUID_SHORT, VARIANCE, WEEK, WEEKDAY, YEAR, YEARMONTH, YEARWEEK` |
1717
| Oracle | `CEIL, DAY, FLOOR, HOUR, LISTAGG, MINUTE, MONTH, NVL, SECOND, TO_CHAR, TO_DATE, TRUNC, YEAR` |
1818
| Sqlite | `CASE WHEN THEN ELSE END, DATE, DATE_FORMAT*, DAY, HOUR, IFNULL, JULIANDAY, MINUTE, MONTH, REPLACE, ROUND, SECOND, STRFTIME, WEEK, WEEKDAY, YEAR` |
1919
| PostgreSQL | `AT_TIME_ZONE, COUNT_FILTER, DATE, DATE_PART, DATE_TRUNC, DAY, EXTRACT, GREATEST, HOUR, LEAST, MINUTE, MONTH, REGEXP_REPLACE, SECOND, STRING_AGG, TO_CHAR, TO_DATE, YEAR` |

config/mysql.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ doctrine:
5656
floor: DoctrineExtensions\Query\Mysql\Floor
5757
json_contains: DoctrineExtensions\Query\Mysql\JsonContains
5858
json_depth: DoctrineExtensions\Query\Mysql\JsonDepth
59+
json_length: DoctrineExtensions\Query\Mysql\JsonLength
5960
log: DoctrineExtensions\Query\Mysql\Log
6061
log10: DoctrineExtensions\Query\Mysql\Log10
6162
log2: DoctrineExtensions\Query\Mysql\Log2

src/Query/Mysql/JsonLength.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace DoctrineExtensions\Query\Mysql;
4+
5+
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
6+
use Doctrine\ORM\Query\Lexer;
7+
use Doctrine\ORM\Query\Parser;
8+
use Doctrine\ORM\Query\SqlWalker;
9+
10+
class JsonLength extends FunctionNode
11+
{
12+
protected $target;
13+
14+
protected $path;
15+
16+
public function parse(Parser $parser)
17+
{
18+
$parser->match(Lexer::T_IDENTIFIER);
19+
$parser->match(Lexer::T_OPEN_PARENTHESIS);
20+
21+
$this->target = $parser->StringPrimary();
22+
23+
if ($parser->getLexer()->isNextToken(Lexer::T_COMMA)) {
24+
$parser->match(Lexer::T_COMMA);
25+
26+
$this->path = $parser->StringPrimary();
27+
}
28+
29+
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
30+
}
31+
32+
public function getSql(SqlWalker $sqlWalker)
33+
{
34+
$target = $sqlWalker->walkStringPrimary($this->target);
35+
36+
if ($this->path !== null) {
37+
$path = $sqlWalker->walkStringPrimary($this->path);
38+
39+
return sprintf('JSON_LENGTH(%s, %s)', $target, $path);
40+
}
41+
42+
return sprintf('JSON_LENGTH(%s)', $target);
43+
}
44+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace DoctrineExtensions\Tests\Query\Mysql;
4+
5+
use DoctrineExtensions\Tests\Query\MysqlTestCase;
6+
7+
class JsonLengthTest extends MysqlTestCase
8+
{
9+
public function testJsonLengthWithoutPath(): void
10+
{
11+
$this->assertDqlProducesSql(
12+
"SELECT JSON_LENGTH('{}') from DoctrineExtensions\Tests\Entities\Blank as blank",
13+
"SELECT JSON_LENGTH('{}') AS sclr_0 FROM Blank b0_"
14+
);
15+
}
16+
17+
public function testJsonLengthWithPathAsParam(): void
18+
{
19+
$this->assertDqlProducesSql(
20+
"SELECT JSON_LENGTH('{}', :param) from DoctrineExtensions\Tests\Entities\Blank as blank",
21+
"SELECT JSON_LENGTH('{}', ?) AS sclr_0 FROM Blank b0_"
22+
);
23+
}
24+
25+
public function testJsonLengthWithPathAsExplicit(): void
26+
{
27+
$this->assertDqlProducesSql(
28+
"SELECT JSON_LENGTH('{}', '$[0]') from DoctrineExtensions\Tests\Entities\Blank as blank",
29+
"SELECT JSON_LENGTH('{}', '$[0]') AS sclr_0 FROM Blank b0_"
30+
);
31+
}
32+
}

0 commit comments

Comments
 (0)