Skip to content

Commit

Permalink
[5.7] Improve JSON UPDATE queries on MySQL (#25794)
Browse files Browse the repository at this point in the history
* Simplify MySqlGrammar

* Use bindings for integer/double values on JSON UPDATE query

* Support NULL values on JSON UPDATE query

* Support raw expressions on JSON UPDATE query
  • Loading branch information
staudenmeir authored and taylorotwell committed Sep 27, 2018
1 parent ddf6cae commit d5e035c
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 12 deletions.
11 changes: 3 additions & 8 deletions src/Illuminate/Database/Query/Grammars/MySqlGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -194,13 +194,9 @@ protected function compileUpdateColumns($values)
*/
protected function compileJsonUpdateColumn($key, JsonExpression $value)
{
$path = explode('->', $key);
list($field, $path) = $this->wrapJsonFieldAndPath($key);

$field = $this->wrapValue(array_shift($path));

$accessor = "'$.\"".implode('"."', $path)."\"'";

return "{$field} = json_set({$field}, {$accessor}, {$value->getValue()})";
return "{$field} = json_set({$field}{$path}, {$value->getValue()})";
}

/**
Expand All @@ -215,8 +211,7 @@ protected function compileJsonUpdateColumn($key, JsonExpression $value)
public function prepareBindingsForUpdate(array $bindings, array $values)
{
$values = collect($values)->reject(function ($value, $column) {
return $this->isJsonSelector($column) &&
in_array(gettype($value), ['boolean', 'integer', 'double']);
return $this->isJsonSelector($column) && is_bool($value);
})->all();

return parent::prepareBindingsForUpdate($bindings, $values);
Expand Down
6 changes: 5 additions & 1 deletion src/Illuminate/Database/Query/JsonExpression.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@ public function __construct($value)
*/
protected function getJsonBindingParameter($value)
{
if ($value instanceof Expression) {
return $value->getValue();
}

switch ($type = gettype($value)) {
case 'boolean':
return $value ? 'true' : 'false';
case 'NULL':
case 'integer':
case 'double':
return $value;
case 'string':
return '?';
case 'object':
Expand Down
14 changes: 11 additions & 3 deletions tests/Database/DatabaseQueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2002,7 +2002,7 @@ public function testMySqlUpdateWrappingNestedJson()
$result = $builder->from('users')->where('active', '=', 1)->update(['meta->name->first_name' => 'John', 'meta->name->last_name' => 'Doe']);
}

public function testMySqlUpdateWithJsonRemovesBindingsCorrectly()
public function testMySqlUpdateWithJsonPreparesBindingsCorrectly()
{
$grammar = new \Illuminate\Database\Query\Grammars\MySqlGrammar;
$processor = m::mock('Illuminate\Database\Query\Processors\Processor');
Expand All @@ -2020,11 +2020,19 @@ public function testMySqlUpdateWithJsonRemovesBindingsCorrectly()
$connection->shouldReceive('update')
->once()
->with(
'update `users` set `options` = json_set(`options`, \'$."size"\', 45), `updated_at` = ? where `id` = ?',
['2015-05-26 22:02:06', 0]
'update `users` set `options` = json_set(`options`, \'$."size"\', ?), `updated_at` = ? where `id` = ?',
[45, '2015-05-26 22:02:06', 0]
);
$builder = new Builder($connection, $grammar, $processor);
$builder->from('users')->where('id', '=', 0)->update(['options->size' => 45, 'updated_at' => '2015-05-26 22:02:06']);

$builder = $this->getMySqlBuilder();
$builder->getConnection()->shouldReceive('update')->once()->with('update `users` set `options` = json_set(`options`, \'$."size"\', ?)', [null]);
$builder->from('users')->update(['options->size' => null]);

$builder = $this->getMySqlBuilder();
$builder->getConnection()->shouldReceive('update')->once()->with('update `users` set `options` = json_set(`options`, \'$."size"\', 45)', []);
$builder->from('users')->update(['options->size' => new Raw('45')]);
}

public function testPostgresUpdateWrappingJson()
Expand Down

0 comments on commit d5e035c

Please sign in to comment.