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
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
12 changes: 9 additions & 3 deletions src/Builder/LengthBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
41 changes: 23 additions & 18 deletions tests/Provider/QueryBuilderProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -895,47 +895,52 @@ 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);

return [
...$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],
<<<SQL
(SELECT '[' + STRING_AGG('"' + STRING_ESCAPE(value, 'json') + '"', ',') + ']' AS value FROM (SELECT value FROM OPENJSON('[1,2,3]') UNION SELECT value FROM OPENJSON(:qp0)) AS t)
(SELECT '[' + STRING_AGG('"' + STRING_ESCAPE(value, 'json') + '"', ',') + ']' AS value FROM (SELECT value FROM OPENJSON(:qp0) UNION SELECT value FROM OPENJSON(:qp1)) AS t)
SQL,
[1, 2, 3, 4, 5],
[':qp0' => $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]))],
<<<SQL
(SELECT '[' + STRING_AGG('"' + STRING_ESCAPE(value, 'json') + '"', ',') + ']' AS value FROM (SELECT value FROM OPENJSON('[1,2,3]') UNION SELECT value FROM OPENJSON(:qp0) UNION SELECT value FROM OPENJSON(:qp1) UNION SELECT value FROM OPENJSON((SELECT :qp2))) AS t)
(SELECT '[' + STRING_AGG('"' + STRING_ESCAPE(value, 'json') + '"', ',') + ']' AS value FROM (SELECT value FROM OPENJSON(:qp0) UNION SELECT value FROM OPENJSON(:qp1) UNION SELECT value FROM OPENJSON(:qp2) UNION SELECT value FROM OPENJSON((SELECT :qp3))) AS t)
SQL,
[1, 2, 3, 4, 5, 6, 7, 9, 10],
[
':qp0' => 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),
],
],
];
Expand Down
30 changes: 22 additions & 8 deletions tests/QueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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();
Expand All @@ -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,
);
Expand Down