Skip to content

Commit

Permalink
Merge branch 'master' into fix_batch_insert_with_associative_arrays
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/QueryBuilder/AbstractDMLQueryBuilder.php
#	src/QueryBuilder/DMLQueryBuilderInterface.php
#	tests/Provider/CommandProvider.php
  • Loading branch information
Tigrov committed Nov 4, 2023
2 parents cdb5f5a + 39872b1 commit 1318a7e
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 29 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
## 1.1.2 under development

- Bug #746: Refactor `DMLQueryBuilder` and fix: unique indexes in `upsert()`, column names with table name and brackets, `batchInsert()` with associative arrays, enhanced documentation of `batchInsert()` and `update()` (@Tigrov)
- Enh #746: Refactor `AbstractDMLQueryBuilder` (@Tigrov)
- Bug #746: Fix `AbstractDMLQueryBuilder::upsert()` when unique index is not at the first position of inserted values (@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)
Expand Down
3 changes: 3 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
<issueHandlers>
<MixedAssignment errorLevel="suppress" />
</issueHandlers>
</psalm>
4 changes: 4 additions & 0 deletions src/Command/CommandInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin
* @throws Exception
* @throws InvalidArgumentException
*
* @psalm-param iterable<array-key, array<array-key, mixed>> $rows
*
* Note: The method will quote the `table` and `column` parameters before using them in the generated SQL.
*/
public function batchInsert(string $table, array $columns, iterable $rows): static;
Expand Down Expand Up @@ -820,6 +822,8 @@ public function update(string $table, array $columns, array|string $condition =
* @throws JsonException
* @throws NotSupportedException
*
* @psalm-param array<string, mixed>|QueryInterface $insertColumns
*
* Note: The method will quote the `table` and `insertColumns`, `updateColumns` parameters before using it in the
* generated SQL.
*/
Expand Down
51 changes: 31 additions & 20 deletions src/QueryBuilder/AbstractDMLQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Expression\ExpressionInterface;
use Yiisoft\Db\Query\QueryInterface;
use Yiisoft\Db\Schema\ColumnSchemaInterface;
use Yiisoft\Db\Schema\QuoterInterface;
use Yiisoft\Db\Schema\SchemaInterface;

Expand All @@ -27,6 +28,7 @@
use function array_slice;
use function array_unique;
use function array_values;
use function count;
use function implode;
use function in_array;
use function is_array;
Expand Down Expand Up @@ -59,6 +61,9 @@ public function batchInsert(string $table, array $columns, iterable $rows, array
return '';
}

$values = [];
$columns = $this->getNormalizeColumnNames('', $columns);
$columnSchemas = $this->schema->getTableSchema($table)?->getColumns() ?? [];
$values = [];
$columns = $this->getNormalizeColumnNames($columns);
$columnSchemas = $this->schema->getTableSchema($table)?->getColumns() ?? [];
Expand All @@ -85,7 +90,6 @@ public function batchInsert(string $table, array $columns, iterable $rows, array

$columnKeys = array_fill_keys($columnNames, false);

/** @psalm-var array[] $rows */
foreach ($rows as $row) {
$i = 0;
$placeholders = $columnKeys;
Expand Down Expand Up @@ -248,18 +252,13 @@ protected function prepareInsertValues(string $table, array|QueryInterface $colu

$names = [];
$placeholders = [];
$columns = $this->normalizeColumnNames($columns);
$columns = $this->normalizeColumnNames('', $columns);
$columnSchemas = $this->schema->getTableSchema($table)?->getColumns() ?? [];

/**
* @psalm-var mixed $value
* @psalm-var array<string, mixed> $columns
*/
foreach ($columns as $name => $value) {
$names[] = $this->quoter->quoteColumnName($name);

if (isset($columnSchemas[$name])) {
/** @var mixed $value */
$value = $columnSchemas[$name]->dbTypecast($value);
}

Expand All @@ -286,16 +285,11 @@ protected function prepareInsertValues(string $table, array|QueryInterface $colu
protected function prepareUpdateSets(string $table, array $columns, array $params = []): array
{
$sets = [];
$columns = $this->normalizeColumnNames($columns);
$columns = $this->normalizeColumnNames('', $columns);
$columnSchemas = $this->schema->getTableSchema($table)?->getColumns() ?? [];

/**
* @psalm-var array<string, mixed> $columns
* @psalm-var mixed $value
*/
foreach ($columns as $name => $value) {
if (isset($columnSchemas[$name])) {
/** @psalm-var mixed $value */
$value = $columnSchemas[$name]->dbTypecast($value);
}

Expand All @@ -320,6 +314,7 @@ protected function prepareUpdateSets(string $table, array $columns, array $param
* @throws JsonException
* @throws NotSupportedException
*
* @psalm-param array<string, mixed>|QueryInterface $insertColumns
* @psalm-param Constraint[] $constraints
*
* @return array Array of unique, insert and update quoted column names.
Expand All @@ -334,16 +329,14 @@ protected function prepareUpsertColumns(
if ($insertColumns instanceof QueryInterface) {
[$insertNames] = $this->prepareInsertSelectSubQuery($insertColumns);
} else {
/** @psalm-var array<string, mixed> $insertColumns */
$insertNames = $this->getNormalizeColumnNames(array_keys($insertColumns));
$insertNames = $this->getNormalizeColumnNames('', array_keys($insertColumns));

$insertNames = array_map(
[$this->quoter, 'quoteColumnName'],
$insertNames,
);
}

/** @psalm-var string[] $uniqueNames */
$uniqueNames = $this->getTableUniqueColumnNames($table, $insertNames, $constraints);

if ($updateColumns === true) {
Expand All @@ -366,7 +359,7 @@ protected function prepareUpsertColumns(
*
* @throws JsonException
*
* @return array The quoted column names.
* @return string[] The quoted column names.
*
* @psalm-param Constraint[] $constraints
*/
Expand Down Expand Up @@ -437,30 +430,48 @@ static function (Constraint $constraint) use ($quoter, $columns, &$columnNames):
return array_unique($columnNames);
}

/**
* @return mixed The typecast value of the given column.
*
* @deprecated will be removed in version 2.0.0
*/
protected function getTypecastValue(mixed $value, ColumnSchemaInterface $columnSchema = null): mixed
{
if ($columnSchema) {
return $columnSchema->dbTypecast($value);
}

return $value;
}

/**
* Normalizes the column names.
*
* @param string $table Not used. Could be empty string. Will be removed in version 2.0.0.
* @param array $columns The column data (name => value).
*
* @return array The normalized column names (name => value).
*
* @psalm-return array<string, mixed>
*/
protected function normalizeColumnNames(array $columns): array
protected function normalizeColumnNames(string $table, array $columns): array
{
/** @var string[] $columnNames */
$columnNames = array_keys($columns);
$normalizedNames = $this->getNormalizeColumnNames($columnNames);
$normalizedNames = $this->getNormalizeColumnNames('', $columnNames);

return array_combine($normalizedNames, $columns);
}

/**
* Get normalized column names
*
* @param string $table Not used. Could be empty string. Will be removed in version 2.0.0.
* @param string[] $columns The column names.
*
* @return string[] Normalized column names.
*/
protected function getNormalizeColumnNames(array $columns): array
protected function getNormalizeColumnNames(string $table, array $columns): array
{
foreach ($columns as &$name) {
$name = $this->quoter->ensureColumnName($name);
Expand Down
3 changes: 1 addition & 2 deletions src/QueryBuilder/AbstractQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Yiisoft\Db\QueryBuilder;

use Generator;
use Yiisoft\Db\Command\CommandInterface;
use Yiisoft\Db\Expression\ExpressionInterface;
use Yiisoft\Db\Query\QueryInterface;
Expand Down Expand Up @@ -109,7 +108,7 @@ public function alterColumn(string $table, string $column, ColumnInterface|strin
return $this->ddlBuilder->alterColumn($table, $column, $type);
}

public function batchInsert(string $table, array $columns, iterable|Generator $rows, array &$params = []): string
public function batchInsert(string $table, array $columns, iterable $rows, array &$params = []): string
{
return $this->dmlBuilder->batchInsert($table, $columns, $rows, $params);
}
Expand Down
8 changes: 5 additions & 3 deletions src/QueryBuilder/DMLQueryBuilderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Yiisoft\Db\QueryBuilder;

use Generator;
use JsonException;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -34,7 +33,7 @@ interface DMLQueryBuilderInterface
*
* @param string $table The table to insert new rows into.
* @param string[] $columns The column names of the table.
* @param Generator|iterable $rows The rows to batch-insert into the table.
* @param iterable $rows The rows to batch-insert into the table.
* @param array $params The binding parameters. This parameter exists.
*
* @throws Exception
Expand All @@ -43,12 +42,13 @@ interface DMLQueryBuilderInterface
* @return string The batch INSERT SQL statement.
*
* @psalm-param string[] $columns
* @psalm-param iterable<array-key, array<array-key, mixed>> $rows
*
* Note:
* - That the values in each row must match the corresponding column names.
* - The method will escape the column names, and quote the values to insert.
*/
public function batchInsert(string $table, array $columns, iterable|Generator $rows, array &$params = []): string;
public function batchInsert(string $table, array $columns, iterable $rows, array &$params = []): string;

/**
* Creates a `DELETE` SQL statement.
Expand Down Expand Up @@ -194,6 +194,8 @@ public function update(string $table, array $columns, array|string $condition, a
* @throws JsonException
* @throws NotSupportedException If this isn't supported by the underlying DBMS.
*
* @psalm-param array<string, mixed>|QueryInterface $insertColumns
*
* Note: The method will escape the table and column names.
*/
public function upsert(
Expand Down
3 changes: 1 addition & 2 deletions tests/AbstractQueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace Yiisoft\Db\Tests;

use Closure;
use Generator;
use JsonException;
use PHPUnit\Framework\TestCase;
use stdClass;
Expand Down Expand Up @@ -211,7 +210,7 @@ public function testAlterColumn(): void
*
* @psalm-param array<array-key, string> $columns
*/
public function testBatchInsert(string $table, array $columns, iterable|Generator $rows, string $expected): void
public function testBatchInsert(string $table, array $columns, iterable $rows, string $expected): void
{
$db = $this->getConnection();
Expand Down
3 changes: 1 addition & 2 deletions tests/Db/QueryBuilder/QueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Yiisoft\Db\Tests\Db\QueryBuilder;

use Generator;
use JsonException;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Exception\InvalidArgumentException;
Expand Down Expand Up @@ -48,7 +47,7 @@ public function testAddDefaultValue(): void
/**
* @dataProvider \Yiisoft\Db\Tests\Provider\QueryBuilderProvider::batchInsert
*/
public function testBatchInsert(string $table, array $columns, iterable|Generator $rows, string $expected): void
public function testBatchInsert(string $table, array $columns, iterable $rows, string $expected): void
{
$db = $this->getConnection();

Expand Down

0 comments on commit 1318a7e

Please sign in to comment.