Skip to content

Commit

Permalink
Refactor DMLQueryBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
Tigrov committed Aug 18, 2023
1 parent aa85945 commit 03cf260
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 28 deletions.
40 changes: 12 additions & 28 deletions src/DMLQueryBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
use Yiisoft\Db\QueryBuilder\AbstractDMLQueryBuilder;

use function implode;
use function ltrim;
use function reset;

/**
* Implements a DML (Data Manipulation Language) SQL statements for SQLite Server.
Expand Down Expand Up @@ -45,8 +43,8 @@ public function resetSequence(string $table, int|string $value = null): string
if ($value !== null) {
$value = "'" . ((int) $value - 1) . "'";
} else {
$pk = $tableSchema->getPrimaryKey();
$key = $this->quoter->quoteColumnName(reset($pk));
$key = $tableSchema->getPrimaryKey()[0];
$key = $this->quoter->quoteColumnName($key);
$value = '(SELECT MAX(' . $key . ') FROM ' . $tableName . ')';
}

Expand All @@ -62,11 +60,6 @@ public function upsert(
/** @psalm-var Constraint[] $constraints */
$constraints = [];

/**
* @psalm-var string[] $insertNames
* @psalm-var string[] $updateNames
* @psalm-var array<string, ExpressionInterface|string>|bool $updateColumns
*/
[$uniqueNames, $insertNames, $updateNames] = $this->prepareUpsertColumns(
$table,
$insertColumns,
Expand All @@ -78,20 +71,19 @@ public function upsert(
return $this->insert($table, $insertColumns, $params);
}

/** @psalm-var string[] $placeholders */
[, $placeholders, $values, $params] = $this->prepareInsertValues($table, $insertColumns, $params);

$insertSql = 'INSERT OR IGNORE INTO '
. $this->quoter->quoteTableName($table)
$quotedTableName = $this->quoter->quoteTableName($table);

$insertSql = 'INSERT OR IGNORE INTO ' . $quotedTableName
. (!empty($insertNames) ? ' (' . implode(', ', $insertNames) . ')' : '')
. (!empty($placeholders) ? ' VALUES (' . implode(', ', $placeholders) . ')' : "$values");
. (!empty($placeholders) ? ' VALUES (' . implode(', ', $placeholders) . ')' : ' ' . $values);

if ($updateColumns === false) {
return $insertSql;
}

$updateCondition = ['or'];
$quotedTableName = $this->quoter->quoteTableName($table);

foreach ($constraints as $constraint) {
$constraintCondition = ['and'];
Expand All @@ -106,27 +98,19 @@ public function upsert(

if ($updateColumns === true) {
$updateColumns = [];
foreach ($updateNames as $name) {
$quotedName = $this->quoter->quoteColumnName($name);

if (strrpos($quotedName, '.') === false) {
$quotedName = "(SELECT $quotedName FROM `EXCLUDED`)";
}
$updateColumns[$name] = new Expression($quotedName);
/** @psalm-var string[] $updateNames */
foreach ($updateNames as $quotedName) {
$updateColumns[$quotedName] = new Expression("(SELECT $quotedName FROM `EXCLUDED`)");
}
}

if ($updateColumns === []) {
return $insertSql;
}

/** @psalm-var array $params */
$updateSql = 'WITH "EXCLUDED" ('
. implode(', ', $insertNames)
. ') AS (' . (!empty($placeholders)
? 'VALUES (' . implode(', ', $placeholders) . ')'
: ltrim("$values", ' ')) . ') ' .
$this->update($table, $updateColumns, $updateCondition, $params);
$updateSql = 'WITH "EXCLUDED" (' . implode(', ', $insertNames) . ') AS ('
. (!empty($placeholders) ? 'VALUES (' . implode(', ', $placeholders) . ')' : $values)
. ') ' . $this->update($table, $updateColumns, $updateCondition, $params);

return "$updateSql; $insertSql;";
}
Expand Down
5 changes: 5 additions & 0 deletions tests/Provider/QueryBuilderProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ public static function upsert(): array
WITH "EXCLUDED" (`email`, `address`, `status`, `profile_id`) AS (VALUES (:qp0, :qp1, :qp2, :qp3)) UPDATE `T_upsert` SET `address`=(SELECT `address` FROM `EXCLUDED`), `status`=(SELECT `status` FROM `EXCLUDED`), `profile_id`=(SELECT `profile_id` FROM `EXCLUDED`) WHERE `T_upsert`.`email`=(SELECT `email` FROM `EXCLUDED`); INSERT OR IGNORE INTO `T_upsert` (`email`, `address`, `status`, `profile_id`) VALUES (:qp0, :qp1, :qp2, :qp3);
SQL,
],
'regular values with unique at not the first position' => [
3 => <<<SQL
WITH "EXCLUDED" (`address`, `email`, `status`, `profile_id`) AS (VALUES (:qp0, :qp1, :qp2, :qp3)) UPDATE `T_upsert` SET `address`=(SELECT `address` FROM `EXCLUDED`), `status`=(SELECT `status` FROM `EXCLUDED`), `profile_id`=(SELECT `profile_id` FROM `EXCLUDED`) WHERE `T_upsert`.`email`=(SELECT `email` FROM `EXCLUDED`); INSERT OR IGNORE INTO `T_upsert` (`address`, `email`, `status`, `profile_id`) VALUES (:qp0, :qp1, :qp2, :qp3);
SQL,
],
'regular values with update part' => [
3 => <<<SQL
WITH "EXCLUDED" (`email`, `address`, `status`, `profile_id`) AS (VALUES (:qp0, :qp1, :qp2, :qp3)) UPDATE `T_upsert` SET `address`=:qp4, `status`=:qp5, `orders`=T_upsert.orders + 1 WHERE `T_upsert`.`email`=(SELECT `email` FROM `EXCLUDED`); INSERT OR IGNORE INTO `T_upsert` (`email`, `address`, `status`, `profile_id`) VALUES (:qp0, :qp1, :qp2, :qp3);
Expand Down

0 comments on commit 03cf260

Please sign in to comment.