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 @@ -107,11 +107,11 @@
- Enh #991: Improve types in `ConnectionInterface::transaction()` (@kikara)
- Chg #998: Add `yiisoft/db-implementation` virtual package as dependency (@vjik)
- Chg #999: Remove `requireTransaction()` method and `$isolationLevel` property from `AbstractCommand` (@vjik)
- Enh #1000: Prepare values in `HashCondition` (@vjik)
- Enh #1000: Prepare values in `Columns` (@vjik)
- Chg #1001: Remove `ParamInterface` (@vjik)
- Chg #1001: Add public properties `$type` and `$value` to `Param` class instead of `getType()` and `getValue()` methods that were removed (@vjik)
- Chg #1002: Remove specific condition interfaces (@vjik)
- Chg #1003: Refactor namespace of condition objects and use promoted properties instead of getters (@vjik)
- Chg #1003, #1006: Refactor namespace of condition objects and use promoted properties instead of getters (@vjik)

## 1.3.0 March 21, 2024

Expand Down
31 changes: 16 additions & 15 deletions docs/guide/en/query/where.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The `Yiisoft\Db\Query\Query::where()` method specifies the `WHERE` fragment of a
You can use one of the four formats to specify a `WHERE` condition.

- string format, `status=1`.
- hash format, `['status' => 1, 'type' => 2]`.
- key-value format, `['status' => 1, 'type' => 2]`.
- operator format, `['like', 'name', 'test']`.
- object format, `new LikeCondition('name', 'LIKE', 'test')`.

Expand Down Expand Up @@ -60,7 +60,7 @@ WHERE (`status` = 10) AND (`type` IS NULL) AND (`id` IN (4, 8, 15))

As you can see, the query builder is intelligent enough to handle values that are nulls or arrays.

You can also use subqueries with hash format like the following.
You can also use subqueries with key-value format like the following.

```php
use Yiisoft\Db\Connection\ConnectionInterface;
Expand All @@ -78,7 +78,7 @@ The relevant part of SQL is:
WHERE `id` IN (SELECT `id` FROM `user`)
```

Using the hash format, Yii DB internally applies parameter binding for values, so in contrast to the string format,
Using the key-value format, Yii DB internally applies parameter binding for values, so in contrast to the string format,
here you don't have to add parameters manually.

However, note that Yii DB never escapes column names, so if you pass a variable obtained from the user side as a column
Expand All @@ -104,7 +104,7 @@ Operator format allows you to specify arbitrary conditions in a programmatic way
['operator', 'operand1', 'operand2', ...]
```

Where the operands can each be specified in string format, hash format or operator format recursively,
Where the operands can each be specified in string format, key-value format or operator format recursively,
while the operator can be one of the following:

### and
Expand Down Expand Up @@ -276,16 +276,16 @@ Internally, the formats described are implicitly converted to object format befo
so it's possible to combine formats in a single condition:

```php
use Yiisoft\Db\QueryBuilder\Condition\InCondition;
use Yiisoft\Db\QueryBuilder\Condition\OrCondition;
use Yiisoft\Db\QueryBuilder\Condition\In;
use Yiisoft\Db\QueryBuilder\Condition\OrX;
use Yiisoft\Db\Query\Query;

/** @var Query $query */

$query->andWhere(
new OrCondition(
new OrX(
[
new InCondition('type', 'in', $types),
new In('type', 'in', $types),
['like', 'name', '%good%'],
'disabled=false',
],
Expand All @@ -297,12 +297,13 @@ Conversion from operator format into object format is performed according
to `Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder::conditionClasses` property
that maps operator names to representative class names.

- `AND`, `OR` => `Yiisoft\Db\QueryBuilder\Condition\ConjunctionCondition`;
- `NOT` => `Yiisoft\Db\QueryBuilder\Condition\NotCondition`;
- `IN`, `NOT IN` => `Yiisoft\Db\QueryBuilder\Condition\InCondition`;
- `BETWEEN`, `NOT BETWEEN` => `Yiisoft\Db\QueryBuilder\Condition\BetweenCondition`;
- `ARRAY OVERLAPS` => `Yiisoft\Db\QueryBuilder\Condition\ArrayOverlapsCondition`;
- `JSON OVERLAPS` => `Yiisoft\Db\QueryBuilder\Condition\JsonOverlapsCondition`.
- `AND` => `Yiisoft\Db\QueryBuilder\Condition\AndX`;
- `OR` => `Yiisoft\Db\QueryBuilder\Condition\OrX`;
- `NOT` => `Yiisoft\Db\QueryBuilder\Condition\Not`;
- `IN`, `NOT IN` => `Yiisoft\Db\QueryBuilder\Condition\In`;
- `BETWEEN`, `NOT BETWEEN` => `Yiisoft\Db\QueryBuilder\Condition\Between`;
- `ARRAY OVERLAPS` => `Yiisoft\Db\QueryBuilder\Condition\ArrayOverlaps`;
- `JSON OVERLAPS` => `Yiisoft\Db\QueryBuilder\Condition\JsonOverlaps`.

## Appending conditions

Expand Down Expand Up @@ -343,7 +344,7 @@ $query->filterWhere(['username' => $username, 'email' => $email]);
```

The only difference between `Yiisoft\Db\Query\Query::filterWhere()` and `Yiisoft\Db\Query\Query::where()`
is that the former will ignore empty values provided in the condition in hash format.
is that the former will ignore empty values provided in the condition in key-value format.

So, if `$email` is empty while `$username` isn't,
the above code will result in the SQL condition `WHERE username=:username`.
Expand Down
19 changes: 11 additions & 8 deletions docs/guide/pt-BR/query/where.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,16 +251,16 @@ Internamente, os formatos descritos são convertidos implicitamente para o forma
então é possível combinar formatos em uma única condição:

```php
use Yiisoft\Db\QueryBuilder\Condition\InCondition;
use Yiisoft\Db\QueryBuilder\Condition\OrCondition;
use Yiisoft\Db\QueryBuilder\Condition\In;
use Yiisoft\Db\QueryBuilder\Condition\OrX;
use Yiisoft\Db\Query\Query;

/** @var Query $query */

$query->andWhere(
new OrCondition(
new OrX(
[
new InCondition('type', 'in', $types),
new In('type', 'in', $types),
['like', 'name', '%good%'],
'disabled=false',
],
Expand All @@ -272,10 +272,13 @@ A conversão do formato operador para o formato objeto é realizada de acordo
com a propriedade `Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder::conditionClasses`
que mapeia nomes de operadores para nomes de classes representativos.

- `AND`, `OR` => `Yiisoft\Db\QueryBuilder\Condition\ConjunctionCondition`.
- `NOT` => `Yiisoft\Db\QueryBuilder\Condition\NotCondition`.
- `IN`, `NOT IN` => `Yiisoft\Db\QueryBuilder\Condition\InCondition`.
- `BETWEEN`, `NOT BETWEEN` => `Yiisoft\Db\QueryBuilder\Condition\BetweenCondition`.
- `AND` => `Yiisoft\Db\QueryBuilder\Condition\AndX`;
- `OR` => `Yiisoft\Db\QueryBuilder\Condition\OrX`;
- `NOT` => `Yiisoft\Db\QueryBuilder\Condition\Not`;
- `IN`, `NOT IN` => `Yiisoft\Db\QueryBuilder\Condition\In`;
- `BETWEEN`, `NOT BETWEEN` => `Yiisoft\Db\QueryBuilder\Condition\Between`;
- `ARRAY OVERLAPS` => `Yiisoft\Db\QueryBuilder\Condition\ArrayOverlaps`;
- `JSON OVERLAPS` => `Yiisoft\Db\QueryBuilder\Condition\JsonOverlaps`.

## Anexando condições

Expand Down
4 changes: 1 addition & 3 deletions src/Query/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -882,9 +882,7 @@ private function filterCondition(array|string $condition): array|string

if (!isset($condition[0])) {
/**
* Hash format: 'column1' => 'value1', 'column2' => 'value2', ...
*
* @psalm-var mixed $value
* Key-value format: 'column1' => 'value1', 'column2' => 'value2', ...
*/
foreach ($condition as $name => $value) {
if ($this->isEmpty($value)) {
Expand Down
4 changes: 2 additions & 2 deletions src/Query/QueryPartsInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -644,10 +644,10 @@ public function union(QueryInterface|string $sql, bool $all = false): static;
*
* The `$condition` specified as an array can be in one of the following two formats:
*
* - hash format: `['column1' => value1, 'column2' => value2, ...]`
* - key-value format: `['column1' => value1, 'column2' => value2, ...]`
* - operator format: `[operator, operand1, operand2, ...]`
*
* A condition in hash format represents the following SQL expression in general:
* A condition in key-value format represents the following SQL expression in general:
* `column1=value1 AND column2=value2 AND ...`. In case when a value is an array,
* an `IN` expression will be generated. And if a value is `null`, `IS NULL` will be used in the generated
* expression. Below are some examples:
Expand Down
63 changes: 33 additions & 30 deletions src/QueryBuilder/AbstractDQLQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
use Yiisoft\Db\Expression\CaseExpressionBuilder;
use Yiisoft\Db\Expression\StructuredExpression;
use Yiisoft\Db\Expression\StructuredExpressionBuilder;
use Yiisoft\Db\QueryBuilder\Condition\HashCondition;
use Yiisoft\Db\QueryBuilder\Condition\Columns;
use Yiisoft\Db\QueryBuilder\Condition\ConditionInterface;
use Yiisoft\Db\QueryBuilder\Condition\SimpleCondition;
use Yiisoft\Db\QueryBuilder\Condition\Simple;
use Yiisoft\Db\Query\Query;
use Yiisoft\Db\Query\QueryExpressionBuilder;
use Yiisoft\Db\Query\QueryInterface;
Expand Down Expand Up @@ -445,12 +445,15 @@ public function createConditionFromArray(array $condition): ConditionInterface
/** operator format: operator, operand 1, operand 2, ... */
if (isset($condition[0])) {
$operator = strtoupper((string) array_shift($condition));
$className = $this->conditionClasses[$operator] ?? SimpleCondition::class;
$className = $this->conditionClasses[$operator] ?? Simple::class;
return $className::fromArrayDefinition($operator, $condition);
}

/** hash format: 'column1' => 'value1', 'column2' => 'value2', ... */
return new HashCondition($condition);
/**
* Key-value format: 'column1' => 'value1', 'column2' => 'value2', ...
* @psalm-var array<string, mixed> $condition
*/
return new Columns($condition);
}

public function getExpressionBuilder(ExpressionInterface $expression): object
Expand Down Expand Up @@ -503,21 +506,21 @@ public function setSeparator(string $separator): void
protected function defaultConditionClasses(): array
{
return [
'NOT' => Condition\NotCondition::class,
'AND' => Condition\AndCondition::class,
'OR' => Condition\OrCondition::class,
'BETWEEN' => Condition\BetweenCondition::class,
'NOT BETWEEN' => Condition\BetweenCondition::class,
'IN' => Condition\InCondition::class,
'NOT IN' => Condition\InCondition::class,
'LIKE' => Condition\LikeCondition::class,
'NOT LIKE' => Condition\LikeCondition::class,
'OR LIKE' => Condition\LikeCondition::class,
'OR NOT LIKE' => Condition\LikeCondition::class,
'EXISTS' => Condition\ExistsCondition::class,
'NOT EXISTS' => Condition\ExistsCondition::class,
'ARRAY OVERLAPS' => Condition\ArrayOverlapsCondition::class,
'JSON OVERLAPS' => Condition\JsonOverlapsCondition::class,
'NOT' => Condition\Not::class,
'AND' => Condition\AndX::class,
'OR' => Condition\OrX::class,
'BETWEEN' => Condition\Between::class,
'NOT BETWEEN' => Condition\Between::class,
'IN' => Condition\In::class,
'NOT IN' => Condition\In::class,
'LIKE' => Condition\Like::class,
'NOT LIKE' => Condition\Like::class,
'OR LIKE' => Condition\Like::class,
'OR NOT LIKE' => Condition\Like::class,
'EXISTS' => Condition\Exists::class,
'NOT EXISTS' => Condition\Exists::class,
'ARRAY OVERLAPS' => Condition\ArrayOverlaps::class,
'JSON OVERLAPS' => Condition\JsonOverlaps::class,
];
}

Expand All @@ -536,16 +539,16 @@ protected function defaultExpressionBuilders(): array
Query::class => QueryExpressionBuilder::class,
Param::class => ParamBuilder::class,
Expression::class => ExpressionBuilder::class,
Condition\NotCondition::class => Condition\Builder\NotConditionBuilder::class,
Condition\AndCondition::class => Condition\Builder\LogicalConditionBuilder::class,
Condition\OrCondition::class => Condition\Builder\LogicalConditionBuilder::class,
Condition\BetweenCondition::class => Condition\Builder\BetweenConditionBuilder::class,
Condition\InCondition::class => Condition\Builder\InConditionBuilder::class,
Condition\LikeCondition::class => Condition\Builder\LikeConditionBuilder::class,
Condition\ExistsCondition::class => Condition\Builder\ExistsConditionBuilder::class,
SimpleCondition::class => Condition\Builder\SimpleConditionBuilder::class,
HashCondition::class => Condition\Builder\HashConditionBuilder::class,
Condition\BetweenColumnsCondition::class => Condition\Builder\BetweenColumnsConditionBuilder::class,
Condition\Not::class => Condition\Builder\NotBuilder::class,
Condition\AndX::class => Condition\Builder\LogicalBuilder::class,
Condition\OrX::class => Condition\Builder\LogicalBuilder::class,
Condition\Between::class => Condition\Builder\BetweenBuilder::class,
Condition\In::class => Condition\Builder\InBuilder::class,
Condition\Like::class => Condition\Builder\LikeBuilder::class,
Condition\Exists::class => Condition\Builder\ExistsBuilder::class,
Simple::class => Condition\Builder\SimpleBuilder::class,
Columns::class => Condition\Builder\ColumnsBuilder::class,
Condition\BetweenColumns::class => Condition\Builder\BetweenColumnsBuilder::class,
JsonExpression::class => JsonExpressionBuilder::class,
ArrayExpression::class => ArrayExpressionBuilder::class,
StructuredExpression::class => StructuredExpressionBuilder::class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/**
* The base class for classes representing the array and JSON overlaps conditions.
*/
abstract class AbstractOverlapsCondition implements ConditionInterface
abstract class AbstractOverlaps implements ConditionInterface
{
/**
* @param ExpressionInterface|string $column The column name or an expression.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/**
* Condition that connects two or more SQL expressions with the `AND` operator.
*/
final class OrCondition implements ConditionInterface
final class AndX implements ConditionInterface
{
/**
* @param array $expressions The expressions that are connected by this condition.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
/**
* Condition that represents `ARRAY OVERLAPS` operator is used to check if a column of array type overlaps another array.
*/
final class ArrayOverlapsCondition extends AbstractOverlapsCondition
final class ArrayOverlaps extends AbstractOverlaps
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
/**
* Condition that's represented `BETWEEN` operator is used to check if a value is between two values.
*/
final class BetweenCondition implements ConditionInterface
final class Between implements ConditionInterface
{
/**
* @param ExpressionInterface|string $column The column name.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
* // NOW() NOT BETWEEN (SELECT time FROM log ORDER BY id ASC LIMIT 1) AND update_time
* ```
*/
final class BetweenColumnsCondition implements ConditionInterface
final class BetweenColumns implements ConditionInterface
{
/**
* @param array|ExpressionInterface|int|Iterator|string $value The value to compare against.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,26 @@
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Expression\ExpressionBuilderInterface;
use Yiisoft\Db\Expression\ExpressionInterface;
use Yiisoft\Db\QueryBuilder\Condition\BetweenCondition;
use Yiisoft\Db\QueryBuilder\Condition\Between;
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;

use function str_contains;

/**
* Build an object of {@see BetweenCondition} into SQL expressions.
* Build an object of {@see Between} into SQL expressions.
*
* @implements ExpressionBuilderInterface<BetweenCondition>
* @implements ExpressionBuilderInterface<Between>
*/
class BetweenConditionBuilder implements ExpressionBuilderInterface
class BetweenBuilder implements ExpressionBuilderInterface
{
public function __construct(private readonly QueryBuilderInterface $queryBuilder)
{
}

/**
* Build SQL for {@see BetweenCondition}.
* Build SQL for {@see Between}.
*
* @param BetweenCondition $expression
* @param Between $expression
*
* @throws Exception
* @throws InvalidArgumentException
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,27 @@
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Expression\ExpressionBuilderInterface;
use Yiisoft\Db\Expression\ExpressionInterface;
use Yiisoft\Db\QueryBuilder\Condition\BetweenColumnsCondition;
use Yiisoft\Db\QueryBuilder\Condition\BetweenColumns;
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;
use Yiisoft\Db\Query\QueryInterface;

use function str_contains;

/**
* Build an object of {@see BetweenColumnsCondition} into SQL expressions.
* Build an object of {@see BetweenColumns} into SQL expressions.
*
* @implements ExpressionBuilderInterface<BetweenColumnsCondition>
* @implements ExpressionBuilderInterface<BetweenColumns>
*/
class BetweenColumnsConditionBuilder implements ExpressionBuilderInterface
class BetweenColumnsBuilder implements ExpressionBuilderInterface
{
public function __construct(private readonly QueryBuilderInterface $queryBuilder)
{
}

/**
* Build SQL for {@see BetweenColumnsCondition}.
* Build SQL for {@see BetweenColumns}.
*
* @param BetweenColumnsCondition $expression
* @param BetweenColumns $expression
*
* @throws Exception
* @throws InvalidArgumentException
Expand Down
Loading