Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not inappropriately register bind when the value is a closure #5247

Merged
merged 8 commits into from Nov 16, 2021

Conversation

vlakoff
Copy link
Contributor

@vlakoff vlakoff commented Oct 27, 2021

Prerequisite for #5138.

The main fix is commit vlakoff@223ca28.

@vlakoff
Copy link
Contributor Author

vlakoff commented Oct 27, 2021

Unless someone figures out realistic unit tests for vlakoff@223ca28 and vlakoff@3e8903a, this PR should be ready.

@vlakoff
Copy link
Contributor Author

vlakoff commented Oct 27, 2021

Also, this change didn't make any test to fail, which points out this precise part of the code isn't covered by unit test. Probably only the string which is normalized afterwards is tested.

I'm not planning to write these unit tests, but it someone wants to do so, be my guest :-)

@vlakoff
Copy link
Contributor Author

vlakoff commented Oct 29, 2021

Actually, there is not a single unit test for "whereHaving" currently, contrarily to "whereIn".
See tests/system/Database/Builder/WhereTest.php.

Maybe someone could be interested in writing these missing unit tests.

@vlakoff vlakoff marked this pull request as ready for review October 29, 2021 07:51
@kenjis
Copy link
Member

kenjis commented Oct 30, 2021

Unit testing tests the object behavior, not in the code, not the specific method.

@kenjis
Copy link
Member

kenjis commented Oct 30, 2021

According to line coverage, there are two lines 682,683 in whereHaving() that are not covered.

$ ./phpunit --coverage-html=build/coverage tests/system/Database/

Screenshot 2021-10-30 11 40 25

@kenjis
Copy link
Member

kenjis commented Oct 30, 2021

The branch coverage for whereHaving() is 84.38%.
Not bad.

$ ./phpunit --coverage-html=build/coverage --path-coverage tests/system/Database/Builder/ -d memory_limit=1024m

Screenshot 2021-10-30 13 15 55

@kenjis
Copy link
Member

kenjis commented Oct 30, 2021

@vlakoff Adding this test gets 100% line coverage.

    public function testWhereAssociateArrayKeyHasEqualValueIsNull()
    {
        $builder = $this->db->table('user');

        $where = [
            'id <'   => 100,
            'col1 =' => null,
        ];
        $builder->where($where);

        $expectedSQL = 'SELECT * FROM "user" WHERE "id" < 100 AND "col1" IS NULL';
        $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect()));
    }

@kenjis
Copy link
Member

kenjis commented Oct 30, 2021

This PR is very good.
The commit messages are great, with clear explanations!

@vlakoff vlakoff force-pushed the db-whereHaving branch 2 times, most recently from 172e044 to 23d0522 Compare October 30, 2021 06:28
@vlakoff
Copy link
Contributor Author

vlakoff commented Oct 30, 2021

I have added this unit test. I made some changes starting from the code you provided:

  • put only the "where" condition we are specifically testing
  • added "$expectedBinds", for the sake of completeness and to show a bind isn't registered

@kenjis
Copy link
Member

kenjis commented Oct 30, 2021

I tried to think of a use case to test vlakoff/CodeIgniter4@4f702d9, but couldn't come up with one.

@kenjis
Copy link
Member

kenjis commented Oct 30, 2021

Okay, line coverage 100%, Branch coverage 93.75%.

Screenshot 2021-10-30 18 49 39

Copy link
Member

@kenjis kenjis left a comment

Choose a reason for hiding this comment

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

I looked at all the commits, and it looks good to me.

system/Database/BaseBuilder.php Outdated Show resolved Hide resolved
system/Database/BaseBuilder.php Outdated Show resolved Hide resolved
Conceptually cleaner, and will be helpful for the next commit.
Such closure just has nothing to do in the $binds array.

The code currently works because the binds compiler determines the binds to apply not by looking at the $binds array, but by looking at the query string, so it doesn't reach the closure.

If we modify the binds compiler to instead look at the $binds array (which makes more sense), it would attempt to replace this registered named bind in the query string, and trying to replace with a closure would trigger a "cannot cast to string" error.
We can simply merge these two blocks.
Exact same effect: this complicated code was for replacing the last occurrence (there is no built-in function for this), and there is an englobing condition to ensure we replace the substring $op only if it is at the very end of $k.

As a bonus, previous code was missing a preg_quote(), but we no longer need it.
If getOperator() found an $op, but it is not at the very end of $k, it does not get removed from $k.

Previous code was nevertheless appending $op, so it got repeated a second time in the result, which is obviously wrong.
This space isn't mandatory, and the query string gets normalized later, adding this space, but let's make it cleanly in the first place.
strtr() is faster for single-character replacements.
For this code path: "elseif (preg_match('/\s*(!?=|<>|IS(?:\s+NOT)?)\s*$/i', $k ..."

The above code path "elseif (! $this->hasOperator($k) ..." is covered in testOrWhereInClosure() and testOrWhereNotInClosure().
@vlakoff
Copy link
Contributor Author

vlakoff commented Nov 5, 2021

Force-pushed, integrating the small code style changes from reviews.

@kenjis kenjis added database Issues or pull requests that affect the database layer refactor Pull requests that refactor code labels Nov 6, 2021
@kenjis kenjis merged commit 0406780 into codeigniter4:develop Nov 16, 2021
@kenjis
Copy link
Member

kenjis commented Nov 16, 2021

@vlakoff Thank you!

@vlakoff vlakoff deleted the db-whereHaving branch November 24, 2021 16:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
database Issues or pull requests that affect the database layer refactor Pull requests that refactor code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants