Skip to content

Commit

Permalink
[9.x] Add the ability to use alias when performing upsert via MySQL (#…
Browse files Browse the repository at this point in the history
…42053)

* Use an alias for the row on upsert.

* Revert "Use an alias for the row on upsert."

This reverts commit 5f1213f.

* Use an alias when compiling upsert when configured.

* wip

* wip

* Handle tests.
  • Loading branch information
paulandroshchuk authored Apr 20, 2022
1 parent beacde8 commit b28c9e1
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 8 deletions.
22 changes: 17 additions & 5 deletions src/Illuminate/Database/Query/Grammars/MySqlGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,24 @@ protected function compileUpdateColumns(Builder $query, array $values)
*/
public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update)
{
$sql = $this->compileInsert($query, $values).' on duplicate key update ';
$useUpsertAlias = $query->connection->getConfig('use_upsert_alias');

$columns = collect($update)->map(function ($value, $key) {
return is_numeric($key)
? $this->wrap($value).' = values('.$this->wrap($value).')'
: $this->wrap($key).' = '.$this->parameter($value);
$sql = $this->compileInsert($query, $values);

if ($useUpsertAlias) {
$sql .= ' as laravel_upsert_alias';
}

$sql .= ' on duplicate key update ';

$columns = collect($update)->map(function ($value, $key) use ($useUpsertAlias) {
if (! is_numeric($key)) {
return $this->wrap($key).' = '.$this->parameter($value);
}

return $useUpsertAlias
? $this->wrap($value).' = '.$this->wrap('laravel_upsert_alias').'.'.$this->wrap($value)
: $this->wrap($value).' = values('.$this->wrap($value).')';
})->implode(', ');

return $sql.$columns;
Expand Down
35 changes: 32 additions & 3 deletions tests/Database/DatabaseQueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2491,7 +2491,16 @@ public function testUpdateMethod()
public function testUpsertMethod()
{
$builder = $this->getMySqlBuilder();
$builder->getConnection()->shouldReceive('affectingStatement')->once()->with('insert into `users` (`email`, `name`) values (?, ?), (?, ?) on duplicate key update `email` = values(`email`), `name` = values(`name`)', ['foo', 'bar', 'foo2', 'bar2'])->andReturn(2);
$builder->getConnection()
->shouldReceive('getConfig')->with('use_upsert_alias')->andReturn(false)
->shouldReceive('affectingStatement')->once()->with('insert into `users` (`email`, `name`) values (?, ?), (?, ?) on duplicate key update `email` = values(`email`), `name` = values(`name`)', ['foo', 'bar', 'foo2', 'bar2'])->andReturn(2);
$result = $builder->from('users')->upsert([['email' => 'foo', 'name' => 'bar'], ['name' => 'bar2', 'email' => 'foo2']], 'email');
$this->assertEquals(2, $result);

$builder = $this->getMySqlBuilder();
$builder->getConnection()
->shouldReceive('getConfig')->with('use_upsert_alias')->andReturn(true)
->shouldReceive('affectingStatement')->once()->with('insert into `users` (`email`, `name`) values (?, ?), (?, ?) as laravel_upsert_alias on duplicate key update `email` = `laravel_upsert_alias`.`email`, `name` = `laravel_upsert_alias`.`name`', ['foo', 'bar', 'foo2', 'bar2'])->andReturn(2);
$result = $builder->from('users')->upsert([['email' => 'foo', 'name' => 'bar'], ['name' => 'bar2', 'email' => 'foo2']], 'email');
$this->assertEquals(2, $result);

Expand All @@ -2514,7 +2523,16 @@ public function testUpsertMethod()
public function testUpsertMethodWithUpdateColumns()
{
$builder = $this->getMySqlBuilder();
$builder->getConnection()->shouldReceive('affectingStatement')->once()->with('insert into `users` (`email`, `name`) values (?, ?), (?, ?) on duplicate key update `name` = values(`name`)', ['foo', 'bar', 'foo2', 'bar2'])->andReturn(2);
$builder->getConnection()
->shouldReceive('getConfig')->with('use_upsert_alias')->andReturn(false)
->shouldReceive('affectingStatement')->once()->with('insert into `users` (`email`, `name`) values (?, ?), (?, ?) on duplicate key update `name` = values(`name`)', ['foo', 'bar', 'foo2', 'bar2'])->andReturn(2);
$result = $builder->from('users')->upsert([['email' => 'foo', 'name' => 'bar'], ['name' => 'bar2', 'email' => 'foo2']], 'email', ['name']);
$this->assertEquals(2, $result);

$builder = $this->getMySqlBuilder();
$builder->getConnection()
->shouldReceive('getConfig')->with('use_upsert_alias')->andReturn(true)
->shouldReceive('affectingStatement')->once()->with('insert into `users` (`email`, `name`) values (?, ?), (?, ?) as laravel_upsert_alias on duplicate key update `name` = `laravel_upsert_alias`.`name`', ['foo', 'bar', 'foo2', 'bar2'])->andReturn(2);
$result = $builder->from('users')->upsert([['email' => 'foo', 'name' => 'bar'], ['name' => 'bar2', 'email' => 'foo2']], 'email', ['name']);
$this->assertEquals(2, $result);

Expand Down Expand Up @@ -2926,7 +2944,18 @@ public function testPreservedAreAppliedByInsertUsing()
public function testPreservedAreAppliedByUpsert()
{
$builder = $this->getMySqlBuilder();
$builder->getConnection()->shouldReceive('affectingStatement')->once()->with('insert into `users` (`email`) values (?) on duplicate key update `email` = values(`email`)', ['foo']);
$builder->getConnection()
->shouldReceive('getConfig')->with('use_upsert_alias')->andReturn(false)
->shouldReceive('affectingStatement')->once()->with('insert into `users` (`email`) values (?) on duplicate key update `email` = values(`email`)', ['foo']);
$builder->beforeQuery(function ($builder) {
$builder->from('users');
});
$builder->upsert(['email' => 'foo'], 'id');

$builder = $this->getMySqlBuilder();
$builder->getConnection()
->shouldReceive('getConfig')->with('use_upsert_alias')->andReturn(true)
->shouldReceive('affectingStatement')->once()->with('insert into `users` (`email`) values (?) as laravel_upsert_alias on duplicate key update `email` = `laravel_upsert_alias`.`email`', ['foo']);
$builder->beforeQuery(function ($builder) {
$builder->from('users');
});
Expand Down

0 comments on commit b28c9e1

Please sign in to comment.