diff --git a/CHANGELOG.md b/CHANGELOG.md index 05e95660..c1290153 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,8 +54,8 @@ - Enh #383: Refactor `TableSchema` and `Schema` classes (@Tigrov) - Enh #386: Support column's collation (@Tigrov) - New #391: Add `Connection::getColumnBuilderClass()` method (@Tigrov) -- New #390, #396: Implement `ArrayMergeBuilder`, `GreatestBuilder`, `LeastBuilder`, `LengthBuilder`, `LongestBuilder` - and `ShortestBuilder` classes (@Tigrov) +- New #390, #396, #404: Implement `ArrayMergeBuilder`, `GreatestBuilder`, `LeastBuilder`, `LengthBuilder`, + `LongestBuilder` and `ShortestBuilder` classes (@Tigrov) - Enh #393: Refactor `DMLQueryBuilder::upsert()` method (@Tigrov) - Chg #398: Update expression namespaces according to changes in `yiisoft/db` package (@Tigrov) - Enh #392: Update `DMLQueryBuilder::update()` method to adapt changes in `yiisoft/db` (@rustamwin) diff --git a/src/Builder/LengthBuilder.php b/src/Builder/LengthBuilder.php index cf198f74..796048f2 100644 --- a/src/Builder/LengthBuilder.php +++ b/src/Builder/LengthBuilder.php @@ -32,12 +32,18 @@ public function __construct(private readonly QueryBuilderInterface $queryBuilder */ public function build(ExpressionInterface $expression, array &$params = []): string { - $operand = $expression->operand; + return 'LEN(' . $this->buildOperand($expression->operand, $params) . ')'; + } + /** + * Builds an operand expression. + */ + private function buildOperand(mixed $operand, array &$params): string + { if (is_string($operand)) { - return "LEN($operand)"; + return $this->queryBuilder->getQuoter()->quoteColumnName($operand); } - return 'LEN(' . $this->queryBuilder->buildExpression($operand, $params) . ')'; + return $this->queryBuilder->buildValue($operand, $params); } } diff --git a/tests/Provider/QueryBuilderProvider.php b/tests/Provider/QueryBuilderProvider.php index 40c00841..e09e82fa 100644 --- a/tests/Provider/QueryBuilderProvider.php +++ b/tests/Provider/QueryBuilderProvider.php @@ -895,16 +895,16 @@ public static function multiOperandFunctionBuilder(): array $db->close(); if (version_compare($serverVersion, '16', '<')) { - $data['Greatest with 2 operands'][2] = '(SELECT MAX(value) FROM (SELECT 1 AS value UNION SELECT 1 + 2 AS value) AS t)'; - $data['Greatest with 4 operands'][2] = '(SELECT MAX(value) FROM (SELECT 1 AS value UNION SELECT 1.5 AS value UNION SELECT 1 + 2 AS value UNION SELECT (SELECT 10) AS value) AS t)'; - $data['Least with 2 operands'][2] = '(SELECT MIN(value) FROM (SELECT 1 AS value UNION SELECT 1 + 2 AS value) AS t)'; - $data['Least with 4 operands'][2] = '(SELECT MIN(value) FROM (SELECT 1 AS value UNION SELECT 1.5 AS value UNION SELECT 1 + 2 AS value UNION SELECT (SELECT 10) AS value) AS t)'; + $data['Greatest with 2 operands'][2] = '(SELECT MAX(value) FROM (SELECT 1 AS value UNION SELECT (1 + 2) AS value) AS t)'; + $data['Greatest with 4 operands'][2] = '(SELECT MAX(value) FROM (SELECT 1 AS value UNION SELECT 1.5 AS value UNION SELECT (1 + 2) AS value UNION SELECT (SELECT 10) AS value) AS t)'; + $data['Least with 2 operands'][2] = '(SELECT MIN(value) FROM (SELECT 1 AS value UNION SELECT (1 + 2) AS value) AS t)'; + $data['Least with 4 operands'][2] = '(SELECT MIN(value) FROM (SELECT 1 AS value UNION SELECT 1.5 AS value UNION SELECT (1 + 2) AS value UNION SELECT (SELECT 10) AS value) AS t)'; } - $data['Longest with 2 operands'][2] = "(SELECT TOP 1 value FROM (SELECT 'short' AS value UNION SELECT :qp0 AS value) AS t ORDER BY LEN(value) DESC)"; - $data['Longest with 3 operands'][2] = "(SELECT TOP 1 value FROM (SELECT 'short' AS value UNION SELECT (SELECT 'longest') AS value UNION SELECT :qp0 AS value) AS t ORDER BY LEN(value) DESC)"; - $data['Shortest with 2 operands'][2] = "(SELECT TOP 1 value FROM (SELECT 'short' AS value UNION SELECT :qp0 AS value) AS t ORDER BY LEN(value) ASC)"; - $data['Shortest with 3 operands'][2] = "(SELECT TOP 1 value FROM (SELECT 'short' AS value UNION SELECT (SELECT 'longest') AS value UNION SELECT :qp0 AS value) AS t ORDER BY LEN(value) ASC)"; + $data['Longest with 2 operands'][2] = '(SELECT TOP 1 value FROM (SELECT :qp0 AS value UNION SELECT :qp1 AS value) AS t ORDER BY LEN(value) DESC)'; + $data['Longest with 3 operands'][2] = "(SELECT TOP 1 value FROM (SELECT :qp0 AS value UNION SELECT (SELECT 'longest') AS value UNION SELECT :qp1 AS value) AS t ORDER BY LEN(value) DESC)"; + $data['Shortest with 2 operands'][2] = '(SELECT TOP 1 value FROM (SELECT :qp0 AS value UNION SELECT :qp1 AS value) AS t ORDER BY LEN(value) ASC)'; + $data['Shortest with 3 operands'][2] = "(SELECT TOP 1 value FROM (SELECT :qp0 AS value UNION SELECT (SELECT 'longest') AS value UNION SELECT :qp1 AS value) AS t ORDER BY LEN(value) ASC)"; $stringParam = new Param('[3,4,5]', DataType::STRING); @@ -912,30 +912,35 @@ public static function multiOperandFunctionBuilder(): array ...$data, 'ArrayMerge with 1 operand' => [ ArrayMerge::class, - ["'[1,2,3]'"], - "('[1,2,3]')", + [[1, 2, 3]], + '(:qp0)', [1, 2, 3], + [':qp0' => new Param('[1,2,3]', DataType::STRING)], ], 'ArrayMerge with 2 operands' => [ ArrayMerge::class, - ["'[1,2,3]'", $stringParam], + [[1, 2, 3], $stringParam], << $stringParam], + [ + ':qp0' => new Param('[1,2,3]', DataType::STRING), + ':qp1' => $stringParam, + ], ], 'ArrayMerge with 4 operands' => [ ArrayMerge::class, - ["'[1,2,3]'", [5, 6, 7], $stringParam, self::getDb()->select(new ArrayValue([9, 10]))], + [[1, 2, 3], new ArrayValue([5, 6, 7]), $stringParam, self::getDb()->select(new ArrayValue([9, 10]))], << new Param('[5,6,7]', DataType::STRING), - ':qp1' => $stringParam, - ':qp2' => new Param('[9,10]', DataType::STRING), + ':qp0' => new Param('[1,2,3]', DataType::STRING), + ':qp1' => new Param('[5,6,7]', DataType::STRING), + ':qp2' => $stringParam, + ':qp3' => new Param('[9,10]', DataType::STRING), ], ], ]; diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php index 093ad959..7a2b7745 100644 --- a/tests/QueryBuilderTest.php +++ b/tests/QueryBuilderTest.php @@ -10,6 +10,7 @@ use Yiisoft\Db\Exception\IntegrityException; use InvalidArgumentException; use Yiisoft\Db\Exception\NotSupportedException; +use Yiisoft\Db\Expression\Function\Length; use Yiisoft\Db\Expression\Value\ArrayValue; use Yiisoft\Db\Expression\Statement\CaseX; use Yiisoft\Db\Expression\Expression; @@ -866,6 +867,18 @@ public function testLengthBuilder( parent::testLengthBuilder($operand, $expectedSql, $expectedResult, $expectedParams); } + public function testLengthBuilderWithColumnName(): void + { + $db = $this->getConnection(); + $qb = $db->getQueryBuilder(); + + $length = new Length('column_name'); + $params = []; + + $this->assertSame(self::replaceQuotes('LEN([[column_name]])'), $qb->buildExpression($length, $params)); + $this->assertSame([], $params); + } + #[DataProviderExternal(QueryBuilderProvider::class, 'multiOperandFunctionBuilder')] public function testMultiOperandFunctionBuilder( string $class, @@ -902,8 +915,8 @@ public function testArrayMergeWithOrdering(): void $stringParam = new Param('[4,3,5]', DataType::STRING); $arrayMerge = (new ArrayMerge( - "'[2,1,3]'", - [6, 5, 7], + [2, 1, 3], + new ArrayValue([6, 5, 7]), $stringParam, self::getDb()->select(new ArrayValue([10, 9])), ))->ordered(); @@ -912,18 +925,19 @@ public function testArrayMergeWithOrdering(): void $this->assertSame( "(SELECT '[' + STRING_AGG('\"' + STRING_ESCAPE(value, 'json') + '\"', ',')" . " WITHIN GROUP (ORDER BY value) + ']' AS value FROM (" - . "SELECT value FROM OPENJSON('[2,1,3]')" - . ' UNION SELECT value FROM OPENJSON(:qp0)' + . 'SELECT value FROM OPENJSON(:qp0)' . ' UNION SELECT value FROM OPENJSON(:qp1)' - . ' UNION SELECT value FROM OPENJSON((SELECT :qp2))' + . ' UNION SELECT value FROM OPENJSON(:qp2)' + . ' UNION SELECT value FROM OPENJSON((SELECT :qp3))' . ') AS t)', $qb->buildExpression($arrayMerge, $params) ); Assert::arraysEquals( [ - ':qp0' => new Param('[6,5,7]', DataType::STRING), - ':qp1' => $stringParam, - ':qp2' => new Param('[10,9]', DataType::STRING), + ':qp0' => new Param('[2,1,3]', DataType::STRING), + ':qp1' => new Param('[6,5,7]', DataType::STRING), + ':qp2' => $stringParam, + ':qp3' => new Param('[10,9]', DataType::STRING), ], $params, );