diff --git a/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php index 23c9e6bacf5a..d9350ef7bca0 100755 --- a/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php @@ -194,10 +194,32 @@ protected function compileUpdateColumns($values) // columns and convert it to a parameter value. Then we will concatenate a // list of the columns that can be added into this update query clauses. return collect($values)->map(function ($value, $key) { + if ($this->isJsonSelector($key)) { + return $this->compileJsonUpdateColumn($key, $value); + } + return $this->wrap($key).' = '.$this->parameter($value); })->implode(', '); } + /** + * Prepares a JSON column being updated using the JSONB_SET function. + * + * @param string $key + * @param mixed $value + * @return string + */ + protected function compileJsonUpdateColumn($key, $value) + { + $parts = explode('->', $key); + + $field = $this->wrap(array_shift($parts)); + + $path = '\'{"'.implode('","', $parts).'"}\''; + + return "{$field} = jsonb_set({$field}::jsonb, {$path}, {$this->parameter($value)})"; + } + /** * Compile the "from" clause for an update with a join. * @@ -281,6 +303,12 @@ protected function compileUpdateJoinWheres(Builder $query) */ public function prepareBindingsForUpdate(array $bindings, array $values) { + $values = collect($values)->map(function ($value, $column) { + return $this->isJsonSelector($column) && ! $this->isExpression($value) + ? json_encode($value) + : $value; + })->all(); + // Update statements with "joins" in Postgres use an interesting syntax. We need to // take all of the bindings and put them on the end of this array since they are // added to the end of the "where" clause statements as typical where clauses. diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 158811664efe..06f1f6fc3d09 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -2027,6 +2027,19 @@ public function testMySqlUpdateWithJsonRemovesBindingsCorrectly() $builder->from('users')->where('id', '=', 0)->update(['options->size' => 45, 'updated_at' => '2015-05-26 22:02:06']); } + public function testPostgresUpdateWrappingJson() + { + $builder = $this->getPostgresBuilder(); + $builder->getConnection()->shouldReceive('update') + ->with('update "users" set "options" = jsonb_set("options"::jsonb, \'{"name","first_name"}\', ?)', ['"John"']); + $builder->from('users')->update(['options->name->first_name' => 'John']); + + $builder = $this->getPostgresBuilder(); + $builder->getConnection()->shouldReceive('update') + ->with('update "users" set "options" = jsonb_set("options"::jsonb, \'{"language"}\', \'null\')', []); + $builder->from('users')->update(['options->language' => new Raw("'null'")]); + } + public function testMySqlWrappingJsonWithString() { $builder = $this->getMySqlBuilder();