diff --git a/CHANGELOG.md b/CHANGELOG.md index 033bc60f..c676514b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Chg #297: Remove `QueryBuilder::getColumnType()` child method as legacy code (@Tigrov) - Enh #300: Refactor insert default values (@Tigrov) +- Bug #302: Refactor `DMLQueryBuilder`, related with yiisoft/db#746 (@Tigrov) ## 1.0.1 July 24, 2023 diff --git a/src/DMLQueryBuilder.php b/src/DMLQueryBuilder.php index d2350126..516b76aa 100644 --- a/src/DMLQueryBuilder.php +++ b/src/DMLQueryBuilder.php @@ -9,13 +9,12 @@ use Yiisoft\Db\Exception\InvalidConfigException; use Yiisoft\Db\Exception\NotSupportedException; use Yiisoft\Db\Expression\Expression; -use Yiisoft\Db\Expression\ExpressionInterface; use Yiisoft\Db\Query\Query; use Yiisoft\Db\Query\QueryInterface; use Yiisoft\Db\QueryBuilder\AbstractDMLQueryBuilder; use function implode; -use function reset; +use function str_replace; /** * Implements a DML (Data Manipulation Language) SQL statements for MySQL, MariaDB. @@ -50,8 +49,7 @@ public function resetSequence(string $table, int|string $value = null): string return 'ALTER TABLE ' . $tableName . ' AUTO_INCREMENT=' . $value . ';'; } - $pk = $tableSchema->getPrimaryKey(); - $key = (string) reset($pk); + $key = $tableSchema->getPrimaryKey()[0]; return "SET @new_autoincrement_value := (SELECT MAX(`$key`) + 1 FROM $tableName); SET @sql = CONCAT('ALTER TABLE $tableName AUTO_INCREMENT =', @new_autoincrement_value); @@ -67,12 +65,7 @@ public function upsert( ): string { $insertSql = $this->insert($table, $insertColumns, $params); - /** @psalm-var array $uniqueNames */ - [$uniqueNames, , $updateNames] = $this->prepareUpsertColumns( - $table, - $insertColumns, - $updateColumns, - ); + [$uniqueNames, , $updateNames] = $this->prepareUpsertColumns($table, $insertColumns, $updateColumns); if (empty($uniqueNames)) { return $insertSql; @@ -80,11 +73,9 @@ public function upsert( if ($updateColumns === true) { $updateColumns = []; - /** @psalm-var string $name */ - foreach ($updateNames as $name) { - $updateColumns[$name] = new Expression( - 'VALUES(' . $this->quoter->quoteColumnName($name) . ')' - ); + /** @psalm-var string[] $updateNames */ + foreach ($updateNames as $quotedName) { + $updateColumns[$quotedName] = new Expression('VALUES(' . $quotedName . ')'); } } @@ -92,10 +83,6 @@ public function upsert( return str_replace('INSERT INTO', 'INSERT IGNORE INTO', $insertSql); } - /** - * @psalm-var array $updates - * @psalm-var array $updateColumns - */ [$updates, $params] = $this->prepareUpdateSets($table, $updateColumns, $params); return $insertSql . ' ON DUPLICATE KEY UPDATE ' . implode(', ', $updates); @@ -115,12 +102,13 @@ public function upsert( * @throws InvalidConfigException * @throws NotSupportedException * - * @return array Array of column names, placeholders, values, and params. + * @return array Array of quoted column names, placeholders, values, and params. + * @psalm-return array{0: string[], 1: string[], 2: string, 3: array} */ protected function prepareInsertValues(string $table, QueryInterface|array $columns, array $params = []): array { if (empty($columns)) { - return [[], [], ' VALUES ()', []]; + return [[], [], 'VALUES ()', []]; } return parent::prepareInsertValues($table, $columns, $params); diff --git a/tests/Provider/QueryBuilderProvider.php b/tests/Provider/QueryBuilderProvider.php index 94204c1f..14bdb263 100644 --- a/tests/Provider/QueryBuilderProvider.php +++ b/tests/Provider/QueryBuilderProvider.php @@ -118,6 +118,10 @@ public static function upsert(): array 3 => 'INSERT INTO `T_upsert` (`email`, `address`, `status`, `profile_id`) VALUES (:qp0, :qp1, :qp2, :qp3) ' . 'ON DUPLICATE KEY UPDATE `address`=VALUES(`address`), `status`=VALUES(`status`), `profile_id`=VALUES(`profile_id`)', ], + 'regular values with unique at not the first position' => [ + 3 => 'INSERT INTO `T_upsert` (`address`, `email`, `status`, `profile_id`) VALUES (:qp0, :qp1, :qp2, :qp3) ' . + 'ON DUPLICATE KEY UPDATE `address`=VALUES(`address`), `status`=VALUES(`status`), `profile_id`=VALUES(`profile_id`)', + ], 'regular values with update part' => [ 3 => 'INSERT INTO `T_upsert` (`email`, `address`, `status`, `profile_id`) VALUES (:qp0, :qp1, :qp2, :qp3) ' . 'ON DUPLICATE KEY UPDATE `address`=:qp4, `status`=:qp5, `orders`=T_upsert.orders + 1', diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php index d73e355f..b58f1ad4 100644 --- a/tests/QueryBuilderTest.php +++ b/tests/QueryBuilderTest.php @@ -4,7 +4,6 @@ namespace Yiisoft\Db\Mysql\Tests; -use Generator; use Throwable; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidArgumentException; @@ -143,7 +142,7 @@ public function testAddUnique(string $name, string $table, array|string $columns * @throws InvalidArgumentException * @throws NotSupportedException */ - 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 { parent::testBatchInsert($table, $columns, $rows, $expected); }