Skip to content

Commit

Permalink
Update 'updated_at' when enabled in replace()
Browse files Browse the repository at this point in the history
  • Loading branch information
paulbalandan committed Jun 3, 2021
1 parent 8fbba76 commit e6b10da
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 13 deletions.
13 changes: 11 additions & 2 deletions system/BaseModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -1086,16 +1086,25 @@ public function onlyDeleted()
* @param array|null $data Data
* @param boolean $returnSQL Set to true to return Query String
*
* @throws DataException
*
* @return mixed
*/
public function replace(array $data = null, bool $returnSQL = false)
{
$data = $this->transformDataToArray($data, 'replace');

// Validate data before saving.
if ($data && ! $this->skipValidation && ! $this->cleanRules(true)->validate($data))
if (! $this->skipValidation && ! $this->cleanRules(true)->validate($data))
{
return false;
}

if ($this->useTimestamps && $this->updatedField && ! array_key_exists($this->updatedField, $data))
{
$data[$this->updatedField] = $this->setDate();
}

return $this->doReplace($data, $returnSQL);
}

Expand Down Expand Up @@ -1658,7 +1667,7 @@ protected function objectToRawArray($data, bool $onlyChanged = true, bool $recur
*/
protected function transformDataToArray($data, string $type): array
{
if (! in_array($type, ['insert', 'update'], true))
if (! in_array($type, ['insert', 'update', 'replace'], true))
{
throw new InvalidArgumentException(sprintf('Invalid type "%s" used upon transforming data to array.', $type));
}
Expand Down
35 changes: 24 additions & 11 deletions system/Database/Postgre/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,16 +143,16 @@ public function decrement(string $column, int $value = 1)
/**
* Replace
*
* Compiles an replace into string and runs the query.
* Compiles a replace into string and runs the query.
* Because PostgreSQL doesn't support the replace into command,
* we simply do a DELETE and an INSERT on the first key/value
* combo, assuming that it's either the primary key or a unique key.
*
* @param array $set An associative array of insert values
*
* @return mixed
* @throws DatabaseException
* @internal param true $bool returns the generated SQL, false executes the query.
* @return mixed
*
* @throws DatabaseException
*/
public function replace(array $set = null)
{
Expand All @@ -167,27 +167,40 @@ public function replace(array $set = null)
{
throw new DatabaseException('You must use the "set" method to update an entry.');
}
// @codeCoverageIgnoreStart
return false;
// @codeCoverageIgnoreEnd

return false; // @codeCoverageIgnore
}

$table = $this->QBFrom[0];
$set = $this->binds;

array_walk($set, static function (array &$item) {
$item = $item[0];
});

$key = array_key_first($set);
$value = $set[$key];

$builder = $this->db->table($table);
$exists = $builder->where("$key = $value", null, false)->get()->getFirstRow();
$exists = $builder->where($key, $value, true)->get()->getFirstRow();

if (empty($exists))
if (empty($exists) && $this->testMode)
{
$result = $this->getCompiledInsert();
}
elseif (empty($exists))
{
$result = $builder->insert($set);
}
elseif ($this->testMode)
{
array_shift($set);
$result = $this->where($key, $value, true)->getCompiledUpdate();
}
else
{
array_pop($set);
$result = $builder->update($set, "$key = $value");
array_shift($set);
$result = $builder->where($key, $value, true)->update($set);
}

unset($builder);
Expand Down
30 changes: 30 additions & 0 deletions tests/system/Models/ReplaceModelTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace CodeIgniter\Models;

use Tests\Support\Models\UserModel;

final class ReplaceModelTest extends LiveModelTestCase
{
public function testReplaceRespectsUseTimestamps(): void
{
$this->createModel(UserModel::class);

$data = [
'name' => 'Amanda Holmes',
'email' => 'amanda@holmes.com',
'country' => 'US',
];

$this->model->insert($data);
$data['country'] = 'UK';

$sql = $this->model->replace($data, true);
$this->assertStringNotContainsString('updated_at', $sql);

$this->model = $this->createModel(UserModel::class);
$this->setPrivateProperty($this->model, 'useTimestamps', true);
$sql = $this->model->replace($data, true);
$this->assertStringContainsString('updated_at', $sql);
}
}

0 comments on commit e6b10da

Please sign in to comment.