Skip to content

Commit

Permalink
支持后置 Where 条件
Browse files Browse the repository at this point in the history
  • Loading branch information
Yurunsoft committed Apr 27, 2024
1 parent afb2950 commit f4d7c2c
Show file tree
Hide file tree
Showing 18 changed files with 184 additions and 40 deletions.
36 changes: 36 additions & 0 deletions doc/base/version/2.0-2.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,42 @@ v2.0 是一个非常成功的 LTS 版本,进行了底层重构,增加了强

## 新功能

### v2.1.63

**发布日期:** `2024-00-00`

* 支持后置 Where 条件

### v2.1.61

**发布日期:** `2024-02-19`

* 支持在模型中使用枚举类型的属性值 ([#674](https://github.com/imiphp/imi/pull/580))

* 支持在控制器方法中使用枚举类型的属性值 ([#675](https://github.com/imiphp/imi/pull/580))

* 支持枚举和联合类型的控制器方法参数 ([#676](https://github.com/imiphp/imi/pull/580))

### v2.1.60

**发布日期:** `2024-01-19`

* 支持 YurunHttp 5.0 ([#672](https://github.com/imiphp/imi/pull/672))

### v2.1.58

**发布日期:** `2023-11-20`

* PHP 原生枚举深度支持 ([#646](https://github.com/imiphp/imi/pull/646))

### v2.1.56

**发布日期:** `2023-10-14`

* 新增获取应用请求地址方法 ([#587](https://github.com/imiphp/imi/pull/587))

* 支持获取限流桶内可用数量 ([#588](https://github.com/imiphp/imi/pull/588))

### v2.1.53

**发布日期:** `2023-09-01`
Expand Down
14 changes: 14 additions & 0 deletions doc/components/db/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,20 @@ Db::query()->whereStruct(new \Imi\Db\Query\Where\Where('age', '<', 14), 'or');
Db::query()->orWhereStruct(new \Imi\Db\Query\Where\Where('age', '<', 14));
```

#### postWhere

用法类似 `whereBrackets`,后置 Where 条件

```php
// where `a` = 1 and (`b` = 2 or `c` = 3) and (`d` != 4)
Db::query()->postWhere(static function (\Imi\Db\Query\Interfaces\IQuery $query, \Imi\Db\Query\Interfaces\IWhereCollector $where) {
$whereCollector->where('b', '=', 2)
->orWhere('c', '=', 3);
})
->postWhere(static fn () => new Where('d', '!=', 4, 'or'))
->where('a', '=', 1);
```

#### 全文搜索(fullText)

imi 查询构建器提供的全文搜索功能,不仅支持全文搜索匹配,还支持返回匹配分数和排序等功能。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public function build(...$args): string
$option = $query->getOption();

$sql = 'delete from ' . $option->table->toString($query)
. $this->parseWhere($option->where)
. $this->parseWhere($option->where, $option->postWhere)
. $this->parseOrder($option->order)
;
$query->bindValues($this->params);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function build(...$args): string
. ' from '
. $option->table->toString($query)
. $this->parseJoin($option->join)
. $this->parseWhere($option->where)
. $this->parseWhere($option->where, $option->postWhere)
. $this->parseGroup($option->group)
. $this->parseHaving($option->having)
. $this->parseOrder($option->order)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public function build(...$args): string
}
$sql = 'update ' . $option->table->toString($query) . ' set ' . implode(',', $setStrs)
. $jsonSets
. $this->parseWhere($option->where)
. $this->parseWhere($option->where, $option->postWhere)
. $this->parseOrder($option->order);

$query->bindValues($params);
Expand Down
2 changes: 1 addition & 1 deletion src/Db/Mysql/Query/Builder/DeleteBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public function build(...$args): string

$sql = 'delete from ' . $option->table->toString($query)
. (($option->partition && '' !== ($partition = $option->partition->toString($query))) ? (' PARTITION(' . $partition . ')') : '')
. $this->parseWhere($option->where)
. $this->parseWhere($option->where, $option->postWhere)
. $this->parseOrder($option->order)
. $this->parseLimit($option->offset, $option->limit)
;
Expand Down
2 changes: 1 addition & 1 deletion src/Db/Mysql/Query/Builder/SelectBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function build(...$args): string
. $option->table->toString($query)
. (($option->partition && '' !== ($partition = $option->partition->toString($query))) ? (' PARTITION(' . $partition . ')') : '')
. $this->parseJoin($option->join)
. $this->parseWhere($option->where)
. $this->parseWhere($option->where, $option->postWhere)
. $this->parseGroup($option->group)
. $this->parseHaving($option->having)
. $this->parseOrder($option->order)
Expand Down
2 changes: 1 addition & 1 deletion src/Db/Mysql/Query/Builder/UpdateBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public function build(...$args): string
. (($option->partition && '' !== ($partition = $option->partition->toString($query))) ? (' PARTITION(' . $partition . ')') : '')
. ' set ' . implode(',', $setStrs)
. $jsonSets
. $this->parseWhere($option->where)
. $this->parseWhere($option->where, $option->postWhere)
. $this->parseOrder($option->order)
. $this->parseLimit($option->offset, $option->limit);

Expand Down
30 changes: 17 additions & 13 deletions src/Db/Query/Builder/BaseBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,29 +94,33 @@ protected function parseJoin(array $join): string
* where.
*
* @param \Imi\Db\Query\Interfaces\IBaseWhere[] $where
* @param \Imi\Db\Query\Interfaces\IBaseWhere[] $postWhere
*/
protected function parseWhere(array $where): string
protected function parseWhere(array $where, array $postWhere): string
{
if (!$where)
if (!$where && !$postWhere)
{
return '';
}
$result = [];
$params = &$this->params;
$query = $this->query;
foreach ($where as $item)
foreach ([$where, $postWhere] as $whereList)
{
$sql = $item->toStringWithoutLogic($query);
if ('' === $sql)
foreach ($whereList as $item)
{
continue;
}
$result[] = $item->getLogicalOperator();
$result[] = $sql;
$binds = $item->getBinds();
if ($binds)
{
$params = array_merge($params, $binds);
$sql = $item->toStringWithoutLogic($query);
if ('' === $sql)
{
continue;

Check warning on line 115 in src/Db/Query/Builder/BaseBuilder.php

View check run for this annotation

Codecov / codecov/patch

src/Db/Query/Builder/BaseBuilder.php#L115

Added line #L115 was not covered by tests
}
$result[] = $item->getLogicalOperator();
$result[] = $sql;
$binds = $item->getBinds();
if ($binds)
{
$params = array_merge($params, $binds);
}
}
}
unset($result[0]);
Expand Down
14 changes: 14 additions & 0 deletions src/Db/Query/Interfaces/IBaseWhereCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,4 +187,18 @@ public function whereIsNotNull(string $fieldName, string $logicalOperator = 'and
* @return static
*/
public function orWhereIsNotNull(string $fieldName): self;

/**
* 后置 Whereand 条件.
*
* @return static
*/
public function postWhere(callable $callback, string $logicalOperator = 'and'): self;

/**
* 后置 Whereor 条件.
*
* @return static
*/
public function orPostWhere(callable $callback): self;
}
10 changes: 10 additions & 0 deletions src/Db/Query/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,16 @@ public function whereIsNotNull(string $fieldName, string $logicalOperator = Logi
return $this->whereRaw($this->fieldQuote($fieldName) . ' is not null', $logicalOperator);
}

/**
* {@inheritDoc}
*/
public function postWhere(callable $callback, string $logicalOperator = LogicalOperator::AND): self
{
$this->option->postWhere[] = new WhereBrackets($callback, $logicalOperator);

return $this;
}

/**
* {@inheritDoc}
*/
Expand Down
7 changes: 7 additions & 0 deletions src/Db/Query/QueryOption.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ class QueryOption
*/
public array $where = [];

/**
* 后置 where 条件.
*
* @var \Imi\Db\Query\Interfaces\IBaseWhere[]
*/
public array $postWhere = [];

/**
* join.
*
Expand Down
8 changes: 8 additions & 0 deletions src/Db/Query/Traits/TWhereCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,4 +204,12 @@ protected function parseWhereEx(array $condition): array

return $result;
}

/**
* {@inheritDoc}
*/
public function orPostWhere(callable $callback): self

Check warning on line 211 in src/Db/Query/Traits/TWhereCollector.php

View check run for this annotation

Codecov / codecov/patch

src/Db/Query/Traits/TWhereCollector.php#L211

Added line #L211 was not covered by tests
{
return $this->postWhere($callback, LogicalOperator::OR);

Check warning on line 213 in src/Db/Query/Traits/TWhereCollector.php

View check run for this annotation

Codecov / codecov/patch

src/Db/Query/Traits/TWhereCollector.php#L213

Added line #L213 was not covered by tests
}
}
22 changes: 14 additions & 8 deletions src/Db/Query/Where/WhereBrackets.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,23 @@ public function toStringWithoutLogic(IQuery $query): string
elseif (null === $callResult)
{
$result = '(';
foreach ($whereCollector->getWhere() as $i => $where)
foreach ([
$whereCollector->getWhere(),
$whereCollector->getPostWhere(),
] as $wheres)
{
if (0 === $i)
foreach ($wheres as $i => $where)
{
$result .= $where->toStringWithoutLogic($query);
}
else
{
$result .= ' ' . $where->getLogicalOperator() . ' ' . $where->toStringWithoutLogic($query);
if (0 === $i)
{
$result .= $where->toStringWithoutLogic($query);
}
else
{
$result .= ' ' . $where->getLogicalOperator() . ' ' . $where->toStringWithoutLogic($query);
}
$binds = array_merge($binds, $where->getBinds());
}
$binds = array_merge($binds, $where->getBinds());
}

return $result . ')';
Expand Down
23 changes: 23 additions & 0 deletions src/Db/Query/WhereCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ class WhereCollector implements IWhereCollector
*/
protected array $where = [];

/**
* @var IBaseWhere[]
*/
protected array $postWhere = [];

protected IQuery $query;

public function __construct(IQuery $query)
Expand All @@ -36,6 +41,14 @@ public function getWhere(): array
return $this->where;
}

/**
* @return IBaseWhere[]
*/
public function getPostWhere(): array
{
return $this->postWhere;
}

/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -95,4 +108,14 @@ public function whereIsNotNull(string $fieldName, string $logicalOperator = Logi
{
return $this->whereRaw($this->query->fieldQuote($fieldName) . ' is not null', $logicalOperator);
}

/**
* @return static
*/
public function postWhere(callable $callback, string $logicalOperator = 'and'): self

Check warning on line 115 in src/Db/Query/WhereCollector.php

View check run for this annotation

Codecov / codecov/patch

src/Db/Query/WhereCollector.php#L115

Added line #L115 was not covered by tests
{
$this->postWhere[] = new WhereBrackets($callback, $logicalOperator);

Check warning on line 117 in src/Db/Query/WhereCollector.php

View check run for this annotation

Codecov / codecov/patch

src/Db/Query/WhereCollector.php#L117

Added line #L117 was not covered by tests

return $this;

Check warning on line 119 in src/Db/Query/WhereCollector.php

View check run for this annotation

Codecov / codecov/patch

src/Db/Query/WhereCollector.php#L119

Added line #L119 was not covered by tests
}
}
7 changes: 4 additions & 3 deletions src/Model/SoftDelete/Annotation/SoftDelete.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
*
* @Target("CLASS")
*
* @property string $field 软删除字段名
* @property mixed $default 软删除字段的默认值代表非删除状态
* @property string $field 软删除字段名
* @property mixed $default 软删除字段的默认值代表非删除状态
* @property bool $postWhere 软删除字段查询时是否为后置条件一般用于索引优化可以设为 true默认为 false
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
class SoftDelete extends Base
Expand All @@ -28,7 +29,7 @@ class SoftDelete extends Base
/**
* @param mixed $default
*/
public function __construct(?array $__data = null, string $field = '', $default = 0)
public function __construct(?array $__data = null, string $field = '', $default = 0, bool $postWhere = false)
{
parent::__construct(...\func_get_args());
if ('' === $this->field)
Expand Down
23 changes: 13 additions & 10 deletions src/Model/SoftDelete/Traits/TSoftDelete.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use Imi\Bean\BeanFactory;
use Imi\Db\Query\Interfaces\IQuery;
use Imi\Db\Query\Interfaces\IResult;
use Imi\Db\Query\Where\Where;
use Imi\Db\Query\Interfaces\IWhereCollector;
use Imi\Event\Event;
use Imi\Model\Contract\IModelQuery;
use Imi\Model\Event\ModelEvents;
Expand Down Expand Up @@ -63,9 +63,10 @@ public static function query(?string $poolName = null, ?int $queryType = null, ?
{
/** @var IModelQuery $query */
$query = parent::query($poolName, $queryType, $queryClass, $alias);
$softDeleteAnnotation = self::__getSoftDeleteAnnotation();
$whereMethod = $softDeleteAnnotation->postWhere ? 'postWhere' : 'whereBrackets';

return $query->whereBrackets(static function (IQuery $query) {
$softDeleteAnnotation = self::__getSoftDeleteAnnotation();
return $query->{$whereMethod}(static function (IQuery $query, IWhereCollector $whereCollector) use ($softDeleteAnnotation) {
$table = $query->getOption()->table;
if (null === ($alias = $table->getAlias()))
{
Expand All @@ -87,12 +88,7 @@ public static function query(?string $poolName = null, ?int $queryType = null, ?
{
$fieldTableName = $alias;
}
if (null === $softDeleteAnnotation->default)
{
return new Where($fieldTableName . '.' . $softDeleteAnnotation->field, 'is', null);
}

return new Where($fieldTableName . '.' . $softDeleteAnnotation->field, '=', $softDeleteAnnotation->default);
$whereCollector->where($fieldTableName . '.' . $softDeleteAnnotation->field, null === $softDeleteAnnotation->default ? 'is' : '=', $softDeleteAnnotation->default);
});
}

Expand Down Expand Up @@ -215,7 +211,14 @@ public static function findDeleted(...$ids): ?Model
$query->where($name, '=', $ids[$i]);
}
}
$query->where($softDeleteAnnotation->field, '!=', $softDeleteAnnotation->default);
if ($softDeleteAnnotation->postWhere)
{
$query->postWhere(static fn (IQuery $query, IWhereCollector $whereCollector) => $whereCollector->where($softDeleteAnnotation->field, '!=', $softDeleteAnnotation->default));

Check warning on line 216 in src/Model/SoftDelete/Traits/TSoftDelete.php

View check run for this annotation

Codecov / codecov/patch

src/Model/SoftDelete/Traits/TSoftDelete.php#L216

Added line #L216 was not covered by tests
}
else
{
$query->where($softDeleteAnnotation->field, '!=', $softDeleteAnnotation->default);
}
}

// 查找前
Expand Down
18 changes: 18 additions & 0 deletions tests/unit/Component/Tests/Db/QueryCurdBaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -874,4 +874,22 @@ public function testWhereNull(): void
$this->assertEquals('select * from `test` where `a` is NULL', $query->buildSelectSql());
$this->assertEquals([], $query->getBinds());
}

public function testPostWhere(): void
{
$query = Db::query()->from('test')
->postWhere(static function (IQuery $query, IWhereCollector $whereCollector) {
$whereCollector->where('b', '=', 2)
->orWhere('c', '=', 3);
})
->postWhere(static fn () => new Where('d', '!=', 4, 'or'))
->where('a', '=', 1);
$this->assertEquals('select * from `test` where `a` = :p1 and (`b` = :p2 or `c` = :p3) and (`d` != :p4)', $query->buildSelectSql());
$this->assertEquals([
':p1' => 1,
':p2' => 2,
':p3' => 3,
':p4' => 4,
], $query->getBinds());
}
}

0 comments on commit f4d7c2c

Please sign in to comment.