From 4a2e6f8d88127bc930c103ef8b16d193c7ea65ec Mon Sep 17 00:00:00 2001 From: Tigrov Date: Sun, 12 Oct 2025 14:20:50 +0700 Subject: [PATCH 1/4] Update according changes in `db` --- src/Builder/LengthBuilder.php | 12 ++++++--- tests/Provider/QueryBuilderProvider.php | 33 ++++++++++++++----------- tests/QueryBuilderTest.php | 30 ++++++++++++++++------ 3 files changed, 50 insertions(+), 25 deletions(-) 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..f2065292 100644 --- a/tests/Provider/QueryBuilderProvider.php +++ b/tests/Provider/QueryBuilderProvider.php @@ -901,10 +901,10 @@ public static function multiOperandFunctionBuilder(): array $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..4c83d073 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(static::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, ); From d60d0580d6fc02afb314d18c4051c18ce79ee12a Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Sun, 12 Oct 2025 07:21:15 +0000 Subject: [PATCH 2/4] Apply fixes from StyleCI --- tests/Provider/QueryBuilderProvider.php | 4 ++-- tests/QueryBuilderTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Provider/QueryBuilderProvider.php b/tests/Provider/QueryBuilderProvider.php index f2065292..804678e4 100644 --- a/tests/Provider/QueryBuilderProvider.php +++ b/tests/Provider/QueryBuilderProvider.php @@ -901,9 +901,9 @@ public static function multiOperandFunctionBuilder(): array $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 :qp0 AS value UNION SELECT :qp1 AS value) AS t ORDER BY LEN(value) DESC)"; + $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 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); diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php index 4c83d073..7a2b7745 100644 --- a/tests/QueryBuilderTest.php +++ b/tests/QueryBuilderTest.php @@ -875,7 +875,7 @@ public function testLengthBuilderWithColumnName(): void $length = new Length('column_name'); $params = []; - $this->assertSame(static::replaceQuotes('LEN([[column_name]])'), $qb->buildExpression($length, $params)); + $this->assertSame(self::replaceQuotes('LEN([[column_name]])'), $qb->buildExpression($length, $params)); $this->assertSame([], $params); } @@ -925,7 +925,7 @@ 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(:qp0)" + . 'SELECT value FROM OPENJSON(:qp0)' . ' UNION SELECT value FROM OPENJSON(:qp1)' . ' UNION SELECT value FROM OPENJSON(:qp2)' . ' UNION SELECT value FROM OPENJSON((SELECT :qp3))' From 0566b4f361ff4d91f673f6d7780a20e9147c8971 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Sun, 12 Oct 2025 15:03:48 +0700 Subject: [PATCH 3/4] fix tests --- tests/Provider/QueryBuilderProvider.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Provider/QueryBuilderProvider.php b/tests/Provider/QueryBuilderProvider.php index 804678e4..e09e82fa 100644 --- a/tests/Provider/QueryBuilderProvider.php +++ b/tests/Provider/QueryBuilderProvider.php @@ -895,10 +895,10 @@ 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 :qp0 AS value UNION SELECT :qp1 AS value) AS t ORDER BY LEN(value) DESC)'; From 4a5d2fb7037305fadd1299fd3bfe980d9c622958 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Sun, 12 Oct 2025 15:11:11 +0700 Subject: [PATCH 4/4] Update CHANGELOG.md [skip ci] --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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)