Skip to content

Commit

Permalink
Merge branch 'master' into allow-columninterface-as-type
Browse files Browse the repository at this point in the history
  • Loading branch information
vjik authored Nov 22, 2023
2 parents 61959fe + 8a3d81f commit ed8f5fc
Show file tree
Hide file tree
Showing 23 changed files with 173 additions and 68 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/active-record.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
name: PHP ${{ matrix.php }}-active-record-${{ matrix.os }}

env:
COMPOSER_ROOT_VERSION: 1.1.0
COMPOSER_ROOT_VERSION: 1.2.0
EXTENSIONS: pdo, pdo_mysql, pdo_oci, pdo_pgsql, pdo_sqlite, pdo_sqlsrv-5.10.1

runs-on: ${{ matrix.os }}
Expand Down
23 changes: 23 additions & 0 deletions .github/workflows/bc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
on:
pull_request:
paths:
- 'src/**'
- '.github/workflows/bc.yml'
- 'composer.json'
push:
branches: ['master']
paths:
- 'src/**'
- '.github/workflows/bc.yml'
- 'composer.json'

name: backwards compatibility

jobs:
roave_bc_check:
uses: yiisoft/actions/.github/workflows/bc.yml@master
with:
os: >-
['ubuntu-latest']
php: >-
['8.1']
15 changes: 0 additions & 15 deletions .github/workflows/bc.yml_

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/db-mariadb.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
name: PHP ${{ matrix.php }}-mariadb-${{ matrix.mariadb }}

env:
COMPOSER_ROOT_VERSION: 1.0.0
COMPOSER_ROOT_VERSION: 1.2.0
CURRENT_PACKAGE: db-mysql
EXTENSIONS: pdo, pdo_mysql

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/db-mssql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
name: PHP ${{ matrix.php }}-mssql-${{ matrix.mssql }}

env:
COMPOSER_ROOT_VERSION: 1.0.0
COMPOSER_ROOT_VERSION: 1.2.0
CURRENT_PACKAGE: db-mssql
EXTENSIONS: pdo, pdo_sqlsrv-5.10.1

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/db-mysql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
name: PHP ${{ matrix.php }}-mysql-${{ matrix.mysql }}

env:
COMPOSER_ROOT_VERSION: 1.0.0
COMPOSER_ROOT_VERSION: 1.2.0
CURRENT_PACKAGE: db-mysql
EXTENSIONS: pdo, pdo_mysql

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/db-oracle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:

env:
CURRENT_PACKAGE: db-oracle
COMPOSER_ROOT_VERSION: 1.0.0
COMPOSER_ROOT_VERSION: 1.2.0
EXTENSIONS: pdo, pdo_oci

runs-on: ${{ matrix.os }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/db-pgsql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
name: PHP ${{ matrix.php }}-pgsql-${{ matrix.pgsql }}

env:
COMPOSER_ROOT_VERSION: 1.0.0
COMPOSER_ROOT_VERSION: 1.2.0
CURRENT_PACKAGE: db-pgsql
EXTENSIONS: pdo, pdo_pgsql

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/db-sqlite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
name: PHP ${{ matrix.php }}-sqlite-${{ matrix.os }}

env:
COMPOSER_ROOT_VERSION: 1.0.0
COMPOSER_ROOT_VERSION: 1.2.0
CURRENT_PACKAGE: db-sqlite
EXTENSIONS: pdo, pdo_sqlite

Expand Down
26 changes: 16 additions & 10 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
# Yii Database Change Log

## 1.1.2 under development
## 1.2.1 under development

- Enh #746: Refactor `AbstractDMLQueryBuilder` (@Tigrov)
- Bug #746: Fix `AbstractDMLQueryBuilder::upsert()` when unique index is not at the first position of inserted values (@Tigrov)
- Bug #777: Fix `Query::count()` when it returns an incorrect value if the result is greater
than `PHP_INT_MAX` (@Tigrov)
- Enh #779: Specify result type of `QueryInterface::all()`, `CommandInterface::queryAll()` and
`DbArrayHelper::populate()` methods to `array[]` (@vjik)
- Enh #779: Specify populate closure type in `BatchQueryResultInterface` (@vjik)
- Enh #778: Deprecate unnecessary argument `$rawSql` of `AbstractCommand::internalExecute()` (@Tigrov)

## 1.2.0 November 12, 2023

- Chg #755: Deprecate `TableSchemaInterface::compositeForeignKey()` (@Tigrov)
- Chg #765: Deprecate `SchemaInterface::TYPE_JSONB` (@Tigrov)
- Enh #746: Enhanced documentation of `batchInsert()` and `update()` methods of `DMLQueryBuilderInterface` interface (@Tigrov)
- Enh #756: Refactor `Quoter` (@Tigrov)
- Enh #770: Move methods from concrete `Command` class to `AbstractPdoCommand` class (@Tigrov)
- Bug #746: Typecast values in `AbstractDMLQueryBuilder::batchInsert()` if column names with table name and brackets (@Tigrov)
- Bug #746, #61: Typecast values in `AbstractDMLQueryBuilder::batchInsert()` if values with string keys (@Tigrov)
- Enh #746: Enhanced documentation of `batchInsert()` and `update()` methods of `DMLQueryBuilderInterface` interface (@Tigrov)
- Bug #751: Fix collected debug actions (@xepozz)
- Chg #755: Deprecate `TableSchemaInterface::compositeForeignKey()` (@Tigrov)
- Enh #756: Refactor `Quoter` (@Tigrov)
- Bug #756: Fix `Quoter::quoteSql()` for SQL containing table with prefix (@Tigrov)
- Bug #756: Fix `Quoter::getTableNameParts()` for cases when different quotes for tables and columns (@Tigrov)
- Bug #756: Fix `Quoter::quoteTableName()` for sub-query with alias (@Tigrov)
- Bug #761: Quote aliases of CTE in `WITH` queries (@Tigrov)
- Chg #765: Deprecate `SchemaInterface::TYPE_JSONB` (@Tigrov)
- Enh #770: Move methods from concrete `Command` class to `AbstractPdoCommand` class (@Tigrov)
- Bug #769, #61: Fix `AbstractDMLQueryBuilder::batchInsert()` for values as associative arrays (@Tigrov)

## 1.1.1 August 16, 2023

Expand Down
2 changes: 0 additions & 2 deletions rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector;
use Rector\Config\RectorConfig;
use Rector\Php56\Rector\FunctionLike\AddDefaultValueForUndefinedVariableRector;
use Rector\Php73\Rector\FuncCall\JsonThrowOnErrorRector;
use Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector;
use Rector\Set\ValueObject\LevelSetList;
Expand All @@ -25,7 +24,6 @@

$rectorConfig->skip([
ClosureToArrowFunctionRector::class,
AddDefaultValueForUndefinedVariableRector::class,
JsonThrowOnErrorRector::class,
]);
};
4 changes: 2 additions & 2 deletions src/Command/AbstractCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ abstract protected function internalGetQueryResult(int $queryMode): mixed;
/**
* Executes a prepared statement.
*
* @param string|null $rawSql The rawSql if it has been created.
* @param string|null $rawSql Deprecated. Use `null` value. Will be removed in version 2.0.0.
*
* @throws Exception
* @throws Throwable
Expand Down Expand Up @@ -581,7 +581,7 @@ protected function queryInternal(int $queryMode): mixed
$isReadMode = $this->isReadMode($queryMode);
$this->prepare($isReadMode);

$this->internalExecute($this->getRawSql());
$this->internalExecute(null);

/** @psalm-var mixed $result */
$result = $this->internalGetQueryResult($queryMode);
Expand Down
2 changes: 1 addition & 1 deletion src/Command/CommandInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ public function query(): DataReaderInterface;
* @throws Exception
* @throws Throwable If execution failed.
*
* @return array All rows of the query result. Each array element is an array representing a row of data.
* @return array[] All rows of the query result. Each array element is an array representing a row of data.
* Empty array if the query results in nothing.
*/
public function queryAll(): array;
Expand Down
2 changes: 1 addition & 1 deletion src/Driver/Pdo/AbstractPdoCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ protected function getQueryMode(int $queryMode): string
*
* It's a wrapper around {@see PDOStatement::execute()} to support transactions and retry handlers.
*
* @param string|null $rawSql The rawSql if it has been created.
* @param string|null $rawSql Deprecated. Use `null` value. Will be removed in version 2.0.0.
*
* @throws Exception
* @throws Throwable
Expand Down
5 changes: 2 additions & 3 deletions src/Helper/DbArrayHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -333,9 +333,9 @@ public static function multisort(
* This method is internally used to convert the data fetched from a database into the format as required by this
* query.
*
* @param array $rows The raw query result from a database.
* @param array[] $rows The raw query result from a database.
*
* @psalm-suppress MixedArrayOffset
* @return array[]
*/
public static function populate(array $rows, Closure|string|null $indexBy = null): array
{
Expand All @@ -345,7 +345,6 @@ public static function populate(array $rows, Closure|string|null $indexBy = null

$result = [];

/** @psalm-var array[][] $row */
foreach ($rows as $row) {
/** @psalm-suppress MixedArrayOffset */
$result[self::getValueByPath($row, $indexBy)] = $row;
Expand Down
5 changes: 5 additions & 0 deletions src/Query/BatchQueryResultInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
* ```
*
* @extends Iterator<int|string, mixed>
*
* @psalm-type PopulateClosure=Closure(array[],Closure|string|null): mixed
*/
interface BatchQueryResultInterface extends Iterator
{
Expand Down Expand Up @@ -106,5 +108,8 @@ public function getBatchSize(): int;
*/
public function batchSize(int $value): self;

/**
* @psalm-param PopulateClosure|null $populateMethod
*/
public function setPopulatedMethod(Closure|null $populateMethod = null): self;
}
14 changes: 9 additions & 5 deletions src/Query/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -293,10 +293,14 @@ public function column(): array

public function count(string $sql = '*'): int|string
{
return match ($this->emulateExecution) {
true => 0,
false => is_numeric($count = $this->queryScalar("COUNT($sql)")) ? (int) $count : 0,
};
/** @var int|string|null $count */
$count = $this->queryScalar("COUNT($sql)");

if ($count === null) {
return 0;
}

return $count <= PHP_INT_MAX ? (int) $count : $count;
}

public function createCommand(): CommandInterface
Expand Down Expand Up @@ -662,7 +666,7 @@ public function where(array|string|ExpressionInterface|null $condition, array $p
return $this;
}

public function withQuery(QueryInterface|string $query, ExpressionInterface|string $alias, bool $recursive = false): static
public function withQuery(QueryInterface|string $query, string $alias, bool $recursive = false): static
{
$this->withQueries[] = ['query' => $query, 'alias' => $alias, 'recursive' => $recursive];
return $this;
Expand Down
2 changes: 1 addition & 1 deletion src/Query/QueryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function addParams(array $params): static;
* @throws InvalidConfigException
* @throws Throwable
*
* @return array The query results. If the query results in nothing, it returns an empty array.
* @return array[] The query results. If the query results in nothing, it returns an empty array.
*/
public function all(): array;

Expand Down
5 changes: 2 additions & 3 deletions src/Query/QueryPartsInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -645,11 +645,10 @@ public function where(array|string|ExpressionInterface|null $condition, array $p
* Prepends an SQL statement using `WITH` syntax.
*
* @param QueryInterface|string $query The SQL statement to append using `UNION`.
* @param ExpressionInterface|string $alias The query alias in `WITH` construction.
* To specify the alias in plain SQL, you may pass an instance of {@see ExpressionInterface}.
* @param string $alias The query alias in `WITH` construction.
* @param bool $recursive Its `true` if using `WITH RECURSIVE` and `false` if using `WITH`.
*/
public function withQuery(QueryInterface|string $query, ExpressionInterface|string $alias, bool $recursive = false): static;
public function withQuery(QueryInterface|string $query, string $alias, bool $recursive = false): static;

/**
* Specifies the `WITH` query clause for the query.
Expand Down
37 changes: 21 additions & 16 deletions src/QueryBuilder/AbstractDMLQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

use function array_combine;
use function array_diff;
use function array_fill_keys;
use function array_filter;
use function array_keys;
use function array_map;
Expand Down Expand Up @@ -57,39 +58,45 @@ public function batchInsert(string $table, array $columns, iterable $rows, array

$values = [];
$columns = $this->getNormalizeColumnNames('', $columns);
$columnNames = array_values($columns);
$columnKeys = array_fill_keys($columnNames, false);
$columnSchemas = $this->schema->getTableSchema($table)?->getColumns() ?? [];

foreach ($rows as $row) {
$i = 0;
$placeholders = [];

foreach ($row as $value) {
if (isset($columns[$i], $columnSchemas[$columns[$i]])) {
$value = $columnSchemas[$columns[$i]]->dbTypecast($value);
$placeholders = $columnKeys;

foreach ($row as $key => $value) {
/** @psalm-suppress MixedArrayTypeCoercion */
$columnName = $columns[$key] ?? (isset($columnKeys[$key]) ? $key : $columnNames[$i] ?? $i);
/** @psalm-suppress MixedArrayTypeCoercion */
if (isset($columnSchemas[$columnName])) {
$value = $columnSchemas[$columnName]->dbTypecast($value);
}

if ($value instanceof ExpressionInterface) {
$placeholders[] = $this->queryBuilder->buildExpression($value, $params);
$placeholders[$columnName] = $this->queryBuilder->buildExpression($value, $params);
} else {
$placeholders[] = $this->queryBuilder->bindParam($value, $params);
$placeholders[$columnName] = $this->queryBuilder->bindParam($value, $params);
}

++$i;
}

$values[] = '(' . implode(', ', $placeholders) . ')';
}

if (empty($values)) {
return '';
}

$columns = array_map(
$columnNames = array_map(
[$this->quoter, 'quoteColumnName'],
$columns,
$columnNames,
);

return 'INSERT INTO ' . $this->quoter->quoteTableName($table)
. ' (' . implode(', ', $columns) . ') VALUES ' . implode(', ', $values);
. ' (' . implode(', ', $columnNames) . ') VALUES ' . implode(', ', $values);
}

public function delete(string $table, array|string $condition, array &$params): string
Expand Down Expand Up @@ -430,13 +437,11 @@ protected function normalizeColumnNames(string $table, array $columns): array
*/
protected function getNormalizeColumnNames(string $table, array $columns): array
{
$normalizedNames = [];

foreach ($columns as $name) {
$normalizedName = $this->quoter->ensureColumnName($name);
$normalizedNames[] = $this->quoter->unquoteSimpleColumnName($normalizedName);
foreach ($columns as &$name) {
$name = $this->quoter->ensureColumnName($name);
$name = $this->quoter->unquoteSimpleColumnName($name);
}

return $normalizedNames;
return $columns;
}
}
14 changes: 14 additions & 0 deletions tests/AbstractQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -787,4 +787,18 @@ public function testNormalizeSelect(array|string|Expression $columns, array|stri
$query->select($columns);
$this->assertEquals($expected, $query->getSelect());
}

public function testCountGreaterThanPhpIntMax(): void
{
$query = $this->getMockBuilder(Query::class)
->setConstructorArgs([$this->getConnection()])
->onlyMethods(['queryScalar'])
->getMock();

$query->expects($this->once())
->method('queryScalar')
->willReturn('12345678901234567890');

$this->assertSame('12345678901234567890', $query->count());
}
}
Loading

0 comments on commit ed8f5fc

Please sign in to comment.