Skip to content

Commit

Permalink
修复带 distinct 的分页查询器,记录数量返回不正确 (#571)
Browse files Browse the repository at this point in the history
* 修复带 distinct 的分页查询器,记录数量返回不正确

* 修复 whereBrackets 返回非数组值时,生成的 SQL 不带括号

* 修复

* 修复
  • Loading branch information
Yurunsoft authored Aug 3, 2023
1 parent 38f66f3 commit 0df2a80
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 7 deletions.
9 changes: 6 additions & 3 deletions doc/components/db/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -724,11 +724,16 @@ var_dump(json_encode($data)); // 支持序列化

### 高性能分页查询

原理:
**原理:**

* 先查出记录 id
* 再根据 id 查询记录

**注意:**

* 仅支持 MySQL 数据库
* 不支持 DISTINCT 查询

```php
// 首先准备好查询构建器
$query = Db::query()->from('xxxtable');
Expand All @@ -751,8 +756,6 @@ $limit = 10;
$result = $pagination->paginate($page, $limit);
```

> 仅 MySQL 数据库支持
## 查询执行

### 查询记录
Expand Down
20 changes: 20 additions & 0 deletions src/Db/Query/Interfaces/IWrapField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Imi\Db\Query\Interfaces;

interface IWrapField extends IField
{
public function getSubFields(): array;

public function setSubFields(array $subFields): void;

public function getWrapLeft(): string;

public function setWrapLeft(string $wrapLeft): void;

public function getWrapRight(): string;

public function setWrapRight(string $wrapRight): void;
}
15 changes: 13 additions & 2 deletions src/Db/Query/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -816,8 +816,19 @@ public function paginate(int $page, int $count, array $options = []): IPaginateR
if ($options['total'] ?? true)
{
$query = (clone $this);
$query->option->order = [];
$total = (int) $query->count();
$option = $query->option;
$option->order = [];
if ($option->distinct)
{
$option->field = [
new WrapField('count(distinct ', $option->field ?: ['*'], ')'),
];
$total = (int) $query->select()->getScalar();
}
else
{
$total = (int) $query->count();
}
}
else
{
Expand Down
4 changes: 2 additions & 2 deletions src/Db/Query/Where/WhereBrackets.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,11 @@ public function toStringWithoutLogic(IQuery $query): string
$result = $callResult->toStringWithoutLogic($query);
$binds = array_merge($binds, $callResult->getBinds());

return $result;
return '(' . $result . ')';
}
else
{
return (string) $callResult;
return '(' . $callResult . ')';
}
}
}
108 changes: 108 additions & 0 deletions src/Db/Query/WrapField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php

declare(strict_types=1);

namespace Imi\Db\Query;

use Imi\Db\Query\Interfaces\IQuery;
use Imi\Db\Query\Interfaces\IWrapField;

class WrapField extends Field implements IWrapField
{
protected array $subFields = [];

protected string $wrapLeft = '';

protected string $wrapRight = '';

public function __construct(string $wrapLeft, array $subFields, string $wrapRight, ?string $alias = null)
{
$this->wrapLeft = $wrapLeft;
$this->subFields = $subFields;
$this->wrapRight = $wrapRight;
$this->alias = $alias;
}

public function getSubFields(): array
{
return $this->subFields;
}

public function setSubFields(array $subFields): void
{
$this->subFields = $subFields;
}

public function getWrapLeft(): string
{
return $this->wrapLeft;
}

public function setWrapLeft(string $wrapLeft): void
{
$this->wrapLeft = $wrapLeft;
}

public function getWrapRight(): string
{
return $this->wrapRight;
}

public function setWrapRight(string $wrapRight): void
{
$this->wrapRight = $wrapRight;
}

/**
* {@inheritDoc}
*/
public function toString(IQuery $query): string
{
if (null === $this->alias)
{
$alias = '';
}
else
{
$alias = ' as ' . $query->fieldQuote($this->alias);
}
if ($this->subFields)
{
$result = [];
$binds = &$this->binds;
foreach ($this->subFields as $k => $v)
{
if (\is_int($k))
{
if ($v instanceof Field)
{
$field = $v;
}
else
{
$field = new Field();
$field->setValue($v ?? '', $query);
}
}
else
{
$field = new Field(null, null, $k, $v);
}
$result[] = $field->toString($query);
$fieldBinds = $field->getBinds();
if ($fieldBinds)
{
$binds = array_merge($binds, $fieldBinds);
}
}

$result = implode(',', $result);
}
else
{
$result = parent::toString($query);
}

return $this->wrapLeft . $result . $this->wrapRight . $alias;
}
}
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 @@ -186,6 +186,24 @@ public function testPaginate(array $args): void
$this->assertEquals($expectedData['total'], $result->getTotal());
$this->assertEquals($expectedData['limit'], $result->getLimit());
$this->assertEquals($expectedData['page_count'], $result->getPageCount());

// distinct
$result = $query->distinct()->field('member_id')->from($this->tableArticle)->paginate(1, 1);
$expectedData = [
'list' => [
[
'member_id' => 0,
],
],
'limit' => 1,
'total' => 1,
'page_count' => 1,
];
$this->assertEquals($expectedData, $result->toArray());
$this->assertEquals($expectedData['list'], $result->getList());
$this->assertEquals($expectedData['total'], $result->getTotal());
$this->assertEquals($expectedData['limit'], $result->getLimit());
$this->assertEquals($expectedData['page_count'], $result->getPageCount());
}

/**
Expand Down

0 comments on commit 0df2a80

Please sign in to comment.