orm: select item

This commit is contained in:
Yuri Kuznetsov
2021-07-23 16:37:32 +03:00
parent cccf05db39
commit 0c6f8bb52d
12 changed files with 289 additions and 29 deletions
@@ -68,6 +68,9 @@ class SelectBuilder
private $sourceQuery = null;
/**
* @var SearchParams
*/
private $searchParams = null;
private $applyAccessControlFilter = false;
@@ -0,0 +1,73 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\ORM\Query\Part;
class SelectExpression implements SelectItem
{
private $expression;
private $alias = null;
public function __construct(Expression $expression, ?string $alias = null)
{
$this->expression = $expression;
$this->alias = $alias;
}
public function getExpression(): Expression
{
return $this->expression;
}
public function getAlias(): ?string
{
return $this->alias;
}
public static function create(Expression $expression, ?string $alias = null): self
{
return new self($expression, $alias);
}
public static function fromString(string $expression): self
{
return self::create(
Expression::create($expression)
);
}
public function withAlias(?string $alias): self
{
$obj = clone $this;
$obj->alias = $alias;
return $obj;
}
}
@@ -0,0 +1,37 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\ORM\Query\Part;
interface SelectItem
{
public function getExpression(): Expression;
public function getAlias(): ?string;
}
+21 -3
View File
@@ -30,6 +30,8 @@
namespace Espo\ORM\Query;
use Espo\ORM\Query\Part\WhereClause;
use Espo\ORM\Query\Part\SelectExpression as SelectExpr;
use Espo\ORM\Query\Part\SelectItem;
use RuntimeException;
@@ -43,9 +45,9 @@ class Select implements SelectingQuery
use SelectingTrait;
use BaseTrait;
const ORDER_ASC = 'ASC';
public const ORDER_ASC = 'ASC';
const ORDER_DESC = 'DESC';
public const ORDER_DESC = 'DESC';
/**
* Get an entity type.
@@ -57,10 +59,26 @@ class Select implements SelectingQuery
/**
* Get select items.
*
* @return SelectItem[]
*/
public function getSelect(): array
{
return $this->params['select'] ?? [];
return array_map(
function ($item) {
if (is_array($item) && count($item)) {
return SelectExpr::fromString($item[0])
->withAlias($item[1] ?? null);
}
if (is_string($item)) {
return SelectExpr::fromString($item);
}
throw new RuntimeException("Bad select item.");
},
$this->params['select'] ?? []
);
}
/**
+51 -6
View File
@@ -30,6 +30,7 @@
namespace Espo\ORM\Query;
use Espo\ORM\Query\Part\Expression;
use Espo\ORM\Query\Part\SelectItem;
use InvalidArgumentException;
use RuntimeException;
@@ -126,21 +127,23 @@ class SelectBuilder implements Builder
/**
* Specify SELECT. Columns and expressions to be selected. If not called, then
* all entity attributes will be selected. Passing an array will reset
* previously set items. Passing a string will append an item.
* previously set items. Passing a string|Expression|SelectItem will append the item.
*
* Usage options:
* * `select([$expr1, $expr2, ...])`
* * `select([[$expr1, $alias1], [$expr2, $alias2], ...])`
* * `select([$selectItem1, $selectItem2, ...])`
* * `select(string|Expression $expression)`
* * `select(string|Expression $expression, string $alias)`
* * `select(SelectItem $selectItem)`
*
* @param array|string|Expression $select An array of attributes or one attribute.
* @param array|string|Expression|SelectItem $select An array of expressions or one expression.
* @param string|null $alias An alias. Actual if the first parameter is a string.
*/
public function select($select, ?string $alias = null): self
{
if (is_array($select)) {
$this->params['select'] = $this->normilizeExpressionItemArray($select);
$this->params['select'] = $this->normilizeSelectItemArray($select);
return $this;
}
@@ -148,12 +151,15 @@ class SelectBuilder implements Builder
if ($select instanceof Expression) {
$select = $select->getValue();
}
else if ($select instanceof SelectItem) {
$alias = $alias ?? $select->getAlias();
$select = $select->getExpression()->getValue();
}
if (is_string($select)) {
$this->params['select'] = $this->params['select'] ?? [];
$this->params['select'][] =
$alias ?
$this->params['select'][] = $alias ?
[$select, $alias] :
$select;
@@ -166,7 +172,7 @@ class SelectBuilder implements Builder
/**
* Specify GROUP BY.
* Passing an array will reset previously set items.
* Passing a string will append an item.
* Passing a string|Expression will append an item.
*
* Usage options:
* * `groupBy([$expr1, $expr2, ...])`
@@ -264,4 +270,43 @@ class SelectBuilder implements Builder
return $this;
}
private function normilizeSelectItemArray(array $itemList): array
{
$resultList = [];
foreach ($itemList as $item) {
if ($item instanceof Expression) {
$resultList[] = $item->getValue();
continue;
}
if ($item instanceof SelectItem) {
$resultList[] = $item->getAlias() ?
[$item->getExpression()->getValue(), $item->getAlias()] :
[$item->getExpression()->getValue()];
continue;
}
if (!is_array($item) || !count($item) || !$item[0] instanceof Expression) {
$resultList[] = $item;
continue;
}
$newItem = [$item[0]->getValue()];
if (count($item) > 1) {
$newItem[] = $item[1];
}
$resultList[] = $newItem;
continue;
}
return $resultList;
}
}
+5 -2
View File
@@ -38,6 +38,7 @@ use Espo\ORM\{
Query\Query,
Query\Builder,
Query\Part\Expression,
Query\Part\SelectItem,
};
use ReflectionClass;
@@ -51,15 +52,17 @@ class QueryBuilder
/**
* Specify SELECT. Columns and expressions to be selected. If not called, then
* all entity attributes will be selected. Passing an array will reset
* previously set items. Passing a string will append an item.
* previously set items. Passing a string|Expression|SelectItem will append the item.
*
* Usage options:
* * `select([$expr1, $expr2, ...])`
* * `select([[$expr1, $alias1], [$expr2, $alias2], ...])`
* * `select([$selectItem1, $selectItem2, ...])`
* * `select(string|Expression $expression)`
* * `select(string|Expression $expression, string $alias)`
* * `select(SelectItem $selectItem)`
*
* @param array|string|Expression $select An array of attributes or one attribute.
* @param array|string|Expression|SelectItem $select An array of expressions or one expression.
* @param string|null $alias An alias. Actual if the first parameter is a string.
*/
public function select($select = null, ?string $alias = null): SelectBuilder
@@ -35,6 +35,7 @@ use Espo\ORM\{
EntityManager,
Query\Select,
Query\Part\WhereItem,
Query\Part\SelectItem,
Mapper\RDBMapper,
Repository\RDBRelationSelectBuilder as Builder,
};
@@ -285,15 +286,17 @@ class RDBRelation
/**
* Specify SELECT. Columns and expressions to be selected. If not called, then
* all entity attributes will be selected. Passing an array will reset
* previously set items. Passing a string will append an item.
* previously set items. Passing a string|Expression|SelectItem will append the item.
*
* Usage options:
* * `select([$expr1, $expr2, ...])`
* * `select([[$expr1, $alias1], [$expr2, $alias2], ...])`
* * `select([$selectItem1, $selectItem2, ...])`
* * `select(string|Expression $expression)`
* * `select(string|Expression $expression, string $alias)`
* * `select(SelectItem $selectItem)`
*
* @param array|string|Expression $select An array of attributes or one attribute.
* @param array|string|Expression|SelectItem $select An array of expressions or one expression.
* @param string|null $alias An alias. Actual if the first parameter is a string.
*/
public function select($select = [], ?string $alias = null): Builder
@@ -37,6 +37,7 @@ use Espo\ORM\{
Query\Select,
Query\SelectBuilder,
Query\Part\WhereItem,
Query\Part\SelectItem,
Mapper\Mapper,
};
@@ -363,15 +364,17 @@ class RDBRelationSelectBuilder
/**
* Specify SELECT. Columns and expressions to be selected. If not called, then
* all entity attributes will be selected. Passing an array will reset
* previously set items. Passing a string will append an item.
* previously set items. Passing a string|Expression|SelectItem will append the item.
*
* Usage options:
* * `select([$expr1, $expr2, ...])`
* * `select([[$expr1, $alias1], [$expr2, $alias2], ...])`
* * `select([$selectItem1, $selectItem2, ...])`
* * `select(string|Expression $expression)`
* * `select(string|Expression $expression, string $alias)`
* * `select(SelectItem $selectItem)`
*
* @param array|string|Expression $select An array of attributes or one attribute.
* @param array|string|Expression|SelectItem $select An array of expressions or one expression.
* @param string|null $alias An alias. Actual if the first parameter is a string.
*/
public function select($select, ?string $alias = null): self
@@ -38,6 +38,7 @@ use Espo\ORM\{
Mapper\RDBMapper,
Query\Select,
Query\Part\WhereItem,
Query\Part\SelectItem,
};
use StdClass;
@@ -331,7 +332,7 @@ class RDBRepository extends Repository
$selectItemList = $select->getSelect();
if (empty($selectItemList)) {
if ($selectItemList === []) {
$selectItemList[] = '*';
}
@@ -781,15 +782,17 @@ class RDBRepository extends Repository
/**
* Specify SELECT. Columns and expressions to be selected. If not called, then
* all entity attributes will be selected. Passing an array will reset
* previously set items. Passing a string will append an item.
* previously set items. Passing a string|Expression|SelectItem will append the item.
*
* Usage options:
* * `select([$expr1, $expr2, ...])`
* * `select([[$expr1, $alias1], [$expr2, $alias2], ...])`
* * `select([$selectItem1, $selectItem2, ...])`
* * `select(string|Expression $expression)`
* * `select(string|Expression $expression, string $alias)`
* * `select(SelectItem $selectItem)`
*
* @param array|string|Expression $select An array of attributes or one attribute.
* @param array|string|Expression|SelectItem $select An array of expressions or one expression.
* @param string|null $alias An alias. Actual if the first parameter is a string.
*/
public function select($select = [], ?string $alias = null): RDBSelectBuilder
@@ -37,6 +37,7 @@ use Espo\ORM\{
Query\Select,
Query\SelectBuilder,
Query\Part\WhereItem,
Query\Part\SelectItem,
Mapper\Mapper,
};
@@ -303,15 +304,17 @@ class RDBSelectBuilder
/**
* Specify SELECT. Columns and expressions to be selected. If not called, then
* all entity attributes will be selected. Passing an array will reset
* previously set items. Passing a string will append an item.
* previously set items. Passing a string|Expression|SelectItem will append the item.
*
* Usage options:
* * `select([$expr1, $expr2, ...])`
* * `select([[$expr1, $alias1], [$expr2, $alias2], ...])`
* * `select([$selectItem1, $selectItem2, ...])`
* * `select(string|Expression $expression)`
* * `select(string|Expression $expression, string $alias)`
* * `select(SelectItem $selectItem)`
*
* @param array|string|Expression $select An array of attributes or one attribute.
* @param array|string|Expression|SelectItem $select An array of expressions or one expression.
* @param string|null $alias An alias. Actual if the first parameter is a string.
*/
public function select($select, ?string $alias = null): self
@@ -33,6 +33,7 @@ use Espo\ORM\{
Query\SelectBuilder,
Query\Part\Condition as Cond,
Query\Part\Expression as Expr,
Query\Part\SelectExpression,
};
class SelectBuilderTest extends \PHPUnit\Framework\TestCase
@@ -65,7 +66,14 @@ class SelectBuilderTest extends \PHPUnit\Framework\TestCase
->select('test')
->build();
$this->assertEquals(['id', 'name', 'test'], $select->getSelect());
$this->assertEquals(
[
SelectExpression::fromString('id'),
SelectExpression::fromString('name'),
SelectExpression::fromString('test'),
],
$select->getSelect()
);
}
public function testSelect2()
@@ -76,7 +84,13 @@ class SelectBuilderTest extends \PHPUnit\Framework\TestCase
->select(['id', 'name'])
->build();
$this->assertEquals(['id', 'name'], $select->getSelect());
$this->assertEquals(
[
SelectExpression::fromString('id'),
SelectExpression::fromString('name'),
],
$select->getSelect()
);
}
public function testSelect3()
@@ -86,7 +100,12 @@ class SelectBuilderTest extends \PHPUnit\Framework\TestCase
->select('test', 'hello')
->build();
$this->assertEquals([['test', 'hello']], $select->getSelect());
$this->assertEquals(
[
SelectExpression::fromString('test')->withAlias('hello'),
],
$select->getSelect()
);
}
public function testSelect4()
@@ -96,7 +115,12 @@ class SelectBuilderTest extends \PHPUnit\Framework\TestCase
->select(Expr::create('test'), 'hello')
->build();
$this->assertEquals([['test', 'hello']], $select->getSelect());
$this->assertEquals(
[
SelectExpression::fromString('test')->withAlias('hello'),
],
$select->getSelect()
);
}
public function testSelect5()
@@ -107,7 +131,13 @@ class SelectBuilderTest extends \PHPUnit\Framework\TestCase
->select([Expr::create('id'), Expr::create('name')])
->build();
$this->assertEquals(['id', 'name'], $select->getSelect());
$this->assertEquals(
[
SelectExpression::fromString('id'),
SelectExpression::fromString('name'),
],
$select->getSelect()
);
}
public function testSelect6()
@@ -121,7 +151,34 @@ class SelectBuilderTest extends \PHPUnit\Framework\TestCase
])
->build();
$this->assertEquals([['id', 'id'], ['name', 'name']], $select->getSelect());
$this->assertEquals(
[
SelectExpression::fromString('id')->withAlias('id'),
SelectExpression::fromString('name')->withAlias('name'),
],
$select->getSelect()
);
}
public function testSelect7()
{
$select = $this->builder
->from('Test')
->select([
'id',
SelectExpression::create(Expr::create('name'))
])
->select(SelectExpression::fromString('test')->withAlias('testAlias'))
->build();
$this->assertEquals(
[
SelectExpression::fromString('id'),
SelectExpression::fromString('name'),
SelectExpression::fromString('test')->withAlias('testAlias'),
],
$select->getSelect()
);
}
public function testCloneNotSame()
+15 -3
View File
@@ -36,6 +36,7 @@ use Espo\ORM\{
Query\Update,
Query\Delete,
Query\Union,
Query\Part\SelectExpression,
};
use RuntimeException;
@@ -96,7 +97,13 @@ class QueryBuilderTest extends \PHPUnit\Framework\TestCase
->from('Test')
->build();
$this->assertEquals(['col1', 'col2'], $select->getSelect());
$this->assertEquals(
[
SelectExpression::fromString('col1'),
SelectExpression::fromString('col2'),
],
$select->getSelect()
);
}
public function testSelectFrom2()
@@ -106,7 +113,12 @@ class QueryBuilderTest extends \PHPUnit\Framework\TestCase
->from('Test')
->build();
$this->assertEquals([['col1', 'alias1']], $select->getSelect());
$this->assertEquals(
[
SelectExpression::fromString('col1')->withAlias('alias1')
],
$select->getSelect()
);
}
public function testInsert1()
{
@@ -237,5 +249,5 @@ class QueryBuilderTest extends \PHPUnit\Framework\TestCase
$this->queryBuilder
->union()
->build();
}
}
}