From e6b10da5f0342b77a2eb9270ae7531a7a0d67ee7 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Fri, 14 May 2021 02:26:48 +0800 Subject: [PATCH] Update 'updated_at' when enabled in replace() --- system/BaseModel.php | 13 +++++++-- system/Database/Postgre/Builder.php | 35 ++++++++++++++++-------- tests/system/Models/ReplaceModelTest.php | 30 ++++++++++++++++++++ 3 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 tests/system/Models/ReplaceModelTest.php diff --git a/system/BaseModel.php b/system/BaseModel.php index 75947add1d73..801f754e32b7 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -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); } @@ -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)); } diff --git a/system/Database/Postgre/Builder.php b/system/Database/Postgre/Builder.php index f23d6dc9f685..bd977e793b88 100644 --- a/system/Database/Postgre/Builder.php +++ b/system/Database/Postgre/Builder.php @@ -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) { @@ -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); diff --git a/tests/system/Models/ReplaceModelTest.php b/tests/system/Models/ReplaceModelTest.php new file mode 100644 index 000000000000..f24862da86b1 --- /dev/null +++ b/tests/system/Models/ReplaceModelTest.php @@ -0,0 +1,30 @@ +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); + } +}