Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 34 additions & 4 deletions system/Database/BaseBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -2929,9 +2929,24 @@ protected function _deleteBatch(string $table, array $keys, array $values): stri
*/
public function increment(string $column, int $value = 1)
{
$column = $this->db->protectIdentifiers($column);
return $this->incrementAll([$column => $value]);
}

/**
* Increments multiple numeric columns by the specified values.
*
* @param array<string, int> $columns An array of column => value pairs to increment.
*/
public function incrementAll(array $columns): bool
{
$fields = [];

foreach ($columns as $col => $val) {
$col = $this->db->protectIdentifiers($col);
$fields[$col] = "{$col} + {$val}";
}
Comment on lines +2944 to +2947
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we no longer have runtime type enforcement for each value, we should add a check manually. Something like:

if (! is_int($val)) {
    throw new TypeError(sprintf(
        'Argument #1 ($columns) must contain only int values, %s given for "%s".',
        get_debug_type($val),
        (string) $col,
    ));
}


$sql = $this->_update($this->QBFrom[0], [$column => "{$column} + {$value}"]);
$sql = $this->_update($this->QBFrom[0], $fields);

if (! $this->testMode) {
$this->resetWrite();
Expand All @@ -2949,9 +2964,24 @@ public function increment(string $column, int $value = 1)
*/
public function decrement(string $column, int $value = 1)
{
$column = $this->db->protectIdentifiers($column);
return $this->decrementAll([$column => $value]);
}

/**
* Decrements multiple numeric columns by the specified values.
*
* @param array<string, int> $columns An array of column => value pairs to decrement.
*/
public function decrementAll(array $columns): bool
{
$fields = [];

foreach ($columns as $col => $val) {
$col = $this->db->protectIdentifiers($col);
$fields[$col] = "{$col} - {$val}";
}

$sql = $this->_update($this->QBFrom[0], [$column => "{$column}-{$value}"]);
$sql = $this->_update($this->QBFrom[0], $fields);

if (! $this->testMode) {
$this->resetWrite();
Expand Down
34 changes: 20 additions & 14 deletions system/Database/Postgre/Builder.php
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<?php

declare(strict_types=1);
Expand Down Expand Up @@ -87,17 +87,20 @@
}

/**
* Increments a numeric column by the specified value.
* Increments multiple numeric columns by the specified values.
*
* @return mixed
*
* @throws DatabaseException
* @param array<string, int> $columns An array of column => value pairs to increment.
*/
public function increment(string $column, int $value = 1)
public function incrementAll(array $columns): bool
{
$column = $this->db->protectIdentifiers($column);
$fields = [];

foreach ($columns as $column => $value) {
$column = $this->db->protectIdentifiers($column);
$fields[$column] = "to_number({$column}, '9999999') + {$value}";
}

$sql = $this->_update($this->QBFrom[0], [$column => "to_number({$column}, '9999999') + {$value}"]);
$sql = $this->_update($this->QBFrom[0], $fields);

if (! $this->testMode) {
$this->resetWrite();
Expand All @@ -109,17 +112,20 @@
}

/**
* Decrements a numeric column by the specified value.
* Decrements multiple numeric columns by the specified values.
*
* @return mixed
*
* @throws DatabaseException
* @param array<string, int> $columns An array of column => value pairs to decrement.
*/
public function decrement(string $column, int $value = 1)
public function decrementAll(array $columns): bool
{
$column = $this->db->protectIdentifiers($column);
$fields = [];

foreach ($columns as $column => $value) {
$column = $this->db->protectIdentifiers($column);
$fields[$column] = "to_number({$column}, '9999999') - {$value}";
}

$sql = $this->_update($this->QBFrom[0], [$column => "to_number({$column}, '9999999') - {$value}"]);
$sql = $this->_update($this->QBFrom[0], $fields);

if (! $this->testMode) {
$this->resetWrite();
Expand Down
42 changes: 24 additions & 18 deletions system/Database/SQLSRV/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -232,21 +232,24 @@ protected function _update(string $table, array $values): string
}

/**
* Increments a numeric column by the specified value.
* Increments multiple numeric columns by the specified values.
*
* @return bool
* @param array<string, int> $columns An array of column => value pairs to increment.
*/
public function increment(string $column, int $value = 1)
public function incrementAll(array $columns): bool
{
$column = $this->db->protectIdentifiers($column);
$fields = [];

if ($this->castTextToInt) {
$values = [$column => "CONVERT(VARCHAR(MAX),CONVERT(INT,CONVERT(VARCHAR(MAX), {$column})) + {$value})"];
} else {
$values = [$column => "{$column} + {$value}"];
foreach ($columns as $column => $value) {
$column = $this->db->protectIdentifiers($column);
if ($this->castTextToInt) {
$fields[$column] = "CONVERT(VARCHAR(MAX),CONVERT(INT,CONVERT(VARCHAR(MAX), {$column})) + {$value})";
} else {
$fields[$column] = "{$column} + {$value}";
}
}

$sql = $this->_update($this->QBFrom[0], $values);
$sql = $this->_update($this->QBFrom[0], $fields);

if (! $this->testMode) {
$this->resetWrite();
Expand All @@ -258,21 +261,24 @@ public function increment(string $column, int $value = 1)
}

/**
* Decrements a numeric column by the specified value.
* Decrements multiple numeric columns by the specified values.
*
* @return bool
* @param array<string, int> $columns An array of column => value pairs to decrement.
*/
public function decrement(string $column, int $value = 1)
public function decrementAll(array $columns): bool
{
$column = $this->db->protectIdentifiers($column);
$fields = [];

if ($this->castTextToInt) {
$values = [$column => "CONVERT(VARCHAR(MAX),CONVERT(INT,CONVERT(VARCHAR(MAX), {$column})) - {$value})"];
} else {
$values = [$column => "{$column} + {$value}"];
foreach ($columns as $column => $value) {
$column = $this->db->protectIdentifiers($column);
if ($this->castTextToInt) {
$fields[$column] = "CONVERT(VARCHAR(MAX),CONVERT(INT,CONVERT(VARCHAR(MAX), {$column})) - {$value})";
} else {
$fields[$column] = "{$column} - {$value}";
}
}

$sql = $this->_update($this->QBFrom[0], $values);
$sql = $this->_update($this->QBFrom[0], $fields);

if (! $this->testMode) {
$this->resetWrite();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ public function up(): void
'deleted_at' => ['type' => 'INTEGER', 'constraint' => 11, 'null' => true],
])->addKey('id', true)->createTable('job', true);

// Task Table
$this->forge->addField([
'id' => ['type' => 'INTEGER', 'constraint' => 3, 'auto_increment' => true],
'name' => ['type' => 'VARCHAR', 'constraint' => 40],
'description' => ['type' => 'VARCHAR', 'constraint' => 400, 'null' => true],
'priority' => ['type' => 'VARCHAR', 'constraint' => 40, 'null' => true],
'created_at' => ['type' => 'INTEGER', 'constraint' => 11, 'null' => true],
'updated_at' => ['type' => 'INTEGER', 'constraint' => 11, 'null' => true],
'deleted_at' => ['type' => 'INTEGER', 'constraint' => 11, 'null' => true],
])->addKey('id', true)->createTable('task', true);

// Misc Table
$this->forge->addField([
'id' => ['type' => 'INTEGER', 'constraint' => 3, 'auto_increment' => true],
Expand Down Expand Up @@ -182,6 +193,7 @@ public function down(): void
{
$this->forge->dropTable('user', true);
$this->forge->dropTable('job', true);
$this->forge->dropTable('task', true);
$this->forge->dropTable('misc', true);
$this->forge->dropTable('type_test', true);
$this->forge->dropTable('empty', true);
Expand Down
17 changes: 17 additions & 0 deletions tests/_support/Database/Seeds/CITestSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,23 @@ public function run(): void
'description' => 'Only Coldplay can actually called Musician',
],
],
'task' => [
[
'name' => 'Grocery',
'description' => 'Go to the grocery store and buy some food',
'priority' => '1',
],
[
'name' => 'Write Tests',
'description' => 'Write tests for the application',
'priority' => '2',
],
[
'name' => 'Fix Bug',
'description' => 'Fix the bug and report to the manager',
'priority' => '3',
],
],
'misc' => [
[
'key' => '\\xxxfoo456',
Expand Down
22 changes: 22 additions & 0 deletions tests/system/Database/Live/IncrementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ public function testIncrementWithValue(): void
$this->seeInDatabase('job', ['name' => 'incremental', 'description' => '8']);
}

public function testIncrementAll(): void
{
$this->hasInDatabase('task', ['name' => 'task1', 'description' => '6', 'priority' => '1']);

$this->db->table('task')
->where('name', 'task1')
->incrementAll(['description' => 2, 'priority' => 3]);

$this->seeInDatabase('task', ['name' => 'task1', 'description' => '8', 'priority' => '4']);
}

public function testResetStateAfterIncrement(): void
{
$this->hasInDatabase('job', ['name' => 'account1', 'description' => '10']);
Expand Down Expand Up @@ -87,6 +98,17 @@ public function testDecrementWithValue(): void
$this->seeInDatabase('job', ['name' => 'incremental', 'description' => '4']);
}

public function testDecrementAll(): void
{
$this->hasInDatabase('task', ['name' => 'task2', 'description' => '6', 'priority' => '5']);

$this->db->table('task')
->where('name', 'task2')
->decrementAll(['description' => 2, 'priority' => 3]);

$this->seeInDatabase('task', ['name' => 'task2', 'description' => '4', 'priority' => '2']);
}

public function testResetStateAfterDecrement(): void
{
$this->hasInDatabase('job', ['name' => 'account1', 'description' => '10']);
Expand Down
1 change: 1 addition & 0 deletions tests/system/Database/Live/MetadataTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ protected function setUp(): void
$prefix . 'migrations',
$prefix . 'user',
$prefix . 'job',
$prefix . 'task',
$prefix . 'misc',
$prefix . 'team_members',
$prefix . 'type_test',
Expand Down
2 changes: 2 additions & 0 deletions user_guide_src/source/changelogs/v4.8.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ Database
Query Builder
-------------

- Added new ``incrementAll()`` and ``decrementAll()`` methods to ``CodeIgniter\Database\BaseBuilder`` for performing bulk increment/decrement operations.

Forge
-----

Expand Down
22 changes: 21 additions & 1 deletion user_guide_src/source/database/query_builder.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2034,12 +2034,22 @@ Class Reference
.. php:method:: increment($column[, $value = 1])

:param string $column: The name of the column to increment
:param int $value: The amount to increment in the column
:param int $value: The amount to increment in the column

Increments the value of a field by the specified amount. If the field
is not a numeric field, like a ``VARCHAR``, it will likely be replaced
with ``$value``.

.. php:method:: incrementAll(array $columns)

.. versionadded:: 4.8.0

:param array $columns: An array of column names with their amounts to increment by

Increments the value of multiple fields by the specified amounts. If a field
is not a numeric field, like a ``VARCHAR``, it will likely be replaced
with the amount specified for that field.

.. php:method:: decrement($column[, $value = 1])

:param string $column: The name of the column to decrement
Expand All @@ -2049,6 +2059,16 @@ Class Reference
is not a numeric field, like a ``VARCHAR``, it will likely be replaced
with ``$value``.

.. php:method:: decrementAll(array $columns)

.. versionadded:: 4.8.0

:param array $columns: An array of column names with their amounts to decrement by

Decrements the value of multiple fields by the specified amounts. If a field
is not a numeric field, like a ``VARCHAR``, it will likely be replaced
with the amount specified for that field.

.. php:method:: truncate()

:returns: ``true`` on success, ``false`` on failure, string on test mode
Expand Down
Loading