Skip to content

feat: Add incrementMany() and decrementMany() methods to BaseBuilder and other driver specific builders#10140

Open
patel-vansh wants to merge 12 commits intocodeigniter4:4.8from
patel-vansh:feat/increment-multiple
Open

feat: Add incrementMany() and decrementMany() methods to BaseBuilder and other driver specific builders#10140
patel-vansh wants to merge 12 commits intocodeigniter4:4.8from
patel-vansh:feat/increment-multiple

Conversation

@patel-vansh
Copy link
Copy Markdown
Contributor

@patel-vansh patel-vansh commented Apr 25, 2026

Description
This PR adds two new functions in BaseBuilder.phpincrementMany() and decrementMany(). These two functions enable devs to increment/decrement multiple rows at once atomically.

Also, the increment() and decrement() methods now internally call incrementMany() and decrementMany() respectively to prevent duplicating the logic.

Checklist:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value (without duplication)
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@github-actions github-actions Bot added the 4.8 PRs that target the `4.8` branch. label Apr 25, 2026
Copy link
Copy Markdown
Member

@paulbalandan paulbalandan left a comment

Choose a reason for hiding this comment

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

Have you considered adding a separate incrementAll (or other wording) that will take care of the array, so to minimize the BC break?

PS. The random test failure seems legitimate. I'll deal with that later.

@michalsn
Copy link
Copy Markdown
Member

I also think that incrementMany() or incrementAll() would probably work better.

@paulbalandan paulbalandan added the breaking change Pull requests that may break existing functionalities label Apr 25, 2026
@patel-vansh
Copy link
Copy Markdown
Contributor Author

patel-vansh commented Apr 25, 2026

Yeah, that would avoid BC. I guess incrementAll would be the new method.

Maybe the current increment method calls incrementAll internally? So, there's no duplication of any logic.
@paulbalandan and @michalsn

@michalsn
Copy link
Copy Markdown
Member

Maybe the current increment method calls incrementAll internally? So, there's no duplication of any logic.

I see why not.

@patel-vansh patel-vansh changed the title feat: Add support to increment/decrement multiple columns at once feat: Add incrementAll() and decrementAll() methods to BaseBuilder and other driver specific builders Apr 25, 2026
@paulbalandan paulbalandan removed the breaking change Pull requests that may break existing functionalities label Apr 25, 2026
@patel-vansh
Copy link
Copy Markdown
Contributor Author

Not sure why PHPStan analysis have failed.

@paulbalandan
Copy link
Copy Markdown
Member

You apparently fixed (or renamed) the affected code. Just run composer phpstan:baseline to update the baseline.

Copy link
Copy Markdown
Member

@michalsn michalsn left a comment

Choose a reason for hiding this comment

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

Supporting a more convenient API would be nice:

incrementAll(['one', 'two'], 2)
incrementAll(['one' => 2, 'two' => 3])

What do you think?

Something like:

public function incrementAll(array $columns, int $value = 1): bool
{
    $fields = [];

    if (array_is_list($columns)) {
        foreach ($columns as $column) {
            $column          = $this->db->protectIdentifiers($column);
            $fields[$column] = "{$column} + {$value}";
        }
    } else {
        foreach ($columns as $column => $value) {
            if (! is_int($value)) {
                throw new TypeError(...);
            }

            $column          = $this->db->protectIdentifiers($column);
            $fields[$column] = "{$column} + {$value}";
        }
    }
    
    // ...
}

Comment thread system/Database/BaseBuilder.php
Comment thread system/Database/SQLSRV/Builder.php
Comment thread system/Database/BaseBuilder.php
Comment thread tests/system/Database/Live/IncrementTest.php Outdated
Comment thread tests/system/Database/Live/IncrementTest.php Outdated
Comment thread user_guide_src/source/database/query_builder.rst Outdated
Comment thread system/Database/SQLSRV/Builder.php Outdated
@patel-vansh
Copy link
Copy Markdown
Contributor Author

incrementEach() is also an option.

@patel-vansh
Copy link
Copy Markdown
Contributor Author

I chose incrementAll() over any other as it kind of refers to an All or nothing DB operation. And since it's a single SQL query, it is an All or Nothing operation.

incrementEach() is an option but I think it's the least bottom in the names, as this might refer to some sort of foreach loop.

incrementMany() is an interesting option too.

@patel-vansh patel-vansh changed the title feat: Add incrementAll() and decrementAll() methods to BaseBuilder and other driver specific builders feat: Add incrementMany() and decrementMany() methods to BaseBuilder and other driver specific builders May 3, 2026
Comment thread user_guide_src/source/database/query_builder.rst Outdated
Query Builder
-------------

- Added new ``incrementMany()`` and ``decrementMany()`` methods to ``CodeIgniter\Database\BaseBuilder`` for performing bulk increment/decrement operations.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You have removed the public methods for SQLSRV and Postgre. I think it needs to be displayed in the BC section. I can't write a suggestion well, let them correct me.
The Postgre::increment() method ... has been removed. Added new incrementMany() instead.

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.

increment() and decrement() are still public through inheritance from BaseBuilder. People overriding those methods in their own subclass can still do so. People calling parent::increment() from a subclass still get working behavior.

Comment thread tests/_support/Database/Migrations/20160428212500_Create_test_tables.php Outdated
$fields = [];

foreach ($columns as $col => $val) {
if (! is_int($val)) {
Copy link
Copy Markdown
Contributor

@neznaika0 neznaika0 May 3, 2026

Choose a reason for hiding this comment

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

You forgot to test negative values. The is_int() check will work correctly and the data will be changed incorrectly: field + -1. It is necessary to prohibit these values.

The comment applies to all new methods

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Actually, negative values were allowed in earlier behaviour. increment() method allowed negative values which would actually subtract from the field instead of adding. So, I tried to retain that behaviour. If everyone agrees to change that, I would happily change this to disallow negative values in both incrementMany() and decrementMany() method

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.

I see no problem with allowing negative values. This may be an actively used feature.

@patel-vansh
Copy link
Copy Markdown
Contributor Author

I was looking at the PostgreSQL Builder's failing test cases and found that the current implementation (to_number({$col}, '9999999') + {$val}) was only working for string based columns who wanted to increment numeric values. But native numeric columns will throw errors.

So, here's my suggestion. Instead of "to_number({$col}, '9999999') + {$val}", we use "{$col}::numeric + {$val}" or "CAST({$col} AS numeric) + {$val}" and it will work with both types of columns and AFAIK, it won't be a BC.

@michalsn
Copy link
Copy Markdown
Member

michalsn commented May 5, 2026

"CAST({$col} AS numeric) + {$val}"

sounds reasonable to me. I do not see BC break here.

@patel-vansh patel-vansh force-pushed the feat/increment-multiple branch from d1c5747 to 3127b88 Compare May 6, 2026 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

4.8 PRs that target the `4.8` branch.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants