-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Support IS NULL
checking in Connection#delete()
and Connection#update()
generated criteria, allowing for null
column searches
#2688
Conversation
Can anyone tell me what I should do about adding a test? Should I just pick a number that doesn't exist yet and stick it in a |
Pick the number for this PR for now (2688)
…On 26 Mar 2017 2:39 p.m., "Jonathan Vollebregt" ***@***.***> wrote:
Can anyone tell me what I should do about adding a test? Should I just
pick a number that doesn't exist yet and stick it in a @group annotation
or is there a protocol to follow here?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#2688 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAJakCgC1-OeEoYbzhCjvCy1RW8pExS0ks5rpr7mgaJpZM4MpKH9>
.
|
Thanks! The test is added, so feel free to merge if my points on backwards compatibility are ok |
lib/Doctrine/DBAL/Connection.php
Outdated
$columnList[] = $columnName; | ||
$criteria[] = $columnName . ' = ?'; | ||
$paramValues[] = $value; | ||
if (is_null($value)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we not duplicate this on the two different methods?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see how without passing columnList, criteria and paramValues as references to the helper method. (Which is probably why they're duplicated in the first place) Is that ok?
*/ | ||
public function testUpdateWithIsNull() | ||
{ | ||
$driverMock = $this->createMock('Doctrine\DBAL\Driver'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the ::class
syntax
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I copy pasted these from existing test testUpdateWithSameColumnInDataAndIdentifiers
- I guess the code style has changed since then? I'll get the changes done
->method('connect') | ||
->will($this->returnValue(new DriverConnectionMock())); | ||
|
||
$conn = $this->getMockBuilder('Doctrine\DBAL\Connection') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you extract this to a method (you can also encapsulate $driverMock
there) so that it can be reused on delete()
?
->will($this->returnValue(new DriverConnectionMock())); | ||
|
||
$conn = $this->getMockBuilder('Doctrine\DBAL\Connection') | ||
->setMethods(array('executeUpdate')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the short array syntax
|
||
$conn = $this->getMockBuilder('Doctrine\DBAL\Connection') | ||
->setMethods(array('executeUpdate')) | ||
->setConstructorArgs(array(array('platform' => new Mocks\MockPlatform()), $driverMock)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*/ | ||
public function testDeleteWithIsNull() | ||
{ | ||
$driverMock = $this->createMock('Doctrine\DBAL\Driver'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
->method('connect') | ||
->will($this->returnValue(new DriverConnectionMock())); | ||
|
||
$conn = $this->getMockBuilder('Doctrine\DBAL\Connection') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
->will($this->returnValue(new DriverConnectionMock())); | ||
|
||
$conn = $this->getMockBuilder('Doctrine\DBAL\Connection') | ||
->setMethods(array('executeUpdate')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
$conn = $this->getMockBuilder('Doctrine\DBAL\Connection') | ||
->setMethods(array('executeUpdate')) | ||
->setConstructorArgs(array(array('platform' => new Mocks\MockPlatform()), $driverMock)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a2f8ef2
to
fc7ff5c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concerning my comments about the tests, it might be a good idea to add a simple functional test for each operation, too.
lib/Doctrine/DBAL/Connection.php
Outdated
* @param array &$criteria Output array of criteria | ||
* @param array &$paramValues Output bound values | ||
*/ | ||
protected function setCriteria($identifiers, &$columnList, &$criteria, &$paramValues) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make this method private as it is not meant to be an extension point for derived classes. Also I would suggest naming the method differently as it is not really modifying the state of the object but rather gathering criteria. So renaming it to something like gatherCriteria()
would make sense to me.
lib/Doctrine/DBAL/Connection.php
Outdated
protected function setCriteria($identifiers, &$columnList, &$criteria, &$paramValues) | ||
{ | ||
foreach ($identifiers as $columnName => $value) { | ||
if (is_null($value)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use a null === $value
here
lib/Doctrine/DBAL/Connection.php
Outdated
foreach ($identifiers as $columnName => $value) { | ||
if (is_null($value)) { | ||
$criteria[] = $this->getDatabasePlatform()->getIsNullExpression($columnName); | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid the else
here. You can continue
early at the end of the if
block.
[ | ||
'text' => 'string', | ||
'is_edited' => 'null', | ||
'id' => 'null', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specifying 'null'
type is a bit weird because Doctrine does not have such type. As the testsuite somewhat also serves as API usage documentation I would suggest not promoting misusage here. I am pretty sure that code won't work when actually executed as Doctrine should complain about not knowing null
type.
IMO the best would be to not specify any type for null
values and let Doctrine decide what to do with it. As an alternative, if you want to complete type specification here, you should use the approriate types that reflect the column type like for id
you would probably pass integer
as type.
'name' => 'foo', | ||
], | ||
[ | ||
'id' => 'null', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above. Also specifying a type for null
values here does make even less sense as those values won't be turned into bound parameters.
01532e4
to
d047285
Compare
@deeky666 Addressed your points and added tests to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Status: Needs work.
|
||
$data = $this->_conn->fetchColumn('SELECT COUNT(*) FROM write_table WHERE test_int = 30'); | ||
|
||
$this->assertEquals(1, $data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, use assertCount()
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assertCount isn't used anywhere in the WriteTest file - are you sure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, no matter if the right assertion was used in other tests or not, this must not prevent you to make a proper check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll use count then. As I asked before:
Is there an up to date code style guide somewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which type of assert choose isn't related to CS, it depends on the type of data you need to check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but the data was an int. Choosing between doing the count in the assert or in the query is CS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Status: Needs work.
lib/Doctrine/DBAL/Connection.php
Outdated
* @param array &$criteria Output array of criteria | ||
* @param array &$paramValues Output bound values | ||
*/ | ||
private function gatherCriteria($identifiers, &$columnList, &$criteria, &$paramValues) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can these arguments be declared?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do you mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private function gatherCriteria(array $identifiers, array &$columnList, array &$criteria, array &$paramValues)
Any chance I could get a new review? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Patch looks awesome, but I will need to go through it to remove that by-ref gatherCriteria
signature (returning a triplet instead)
I'll get on that right now then, thanks for the feedback! |
@jnvsor ideally, the result would be |
How should I write up the docstring? Just |
/**
* ...
* @return string[][] a triplet with:
* - the first key being the column list
* - the second key being the criteria string
* - the third key being the bound parameter types
*/ |
4087216
to
e2e3abc
Compare
Ok, I've cleaned it up a bit: /**
* Gathers criteria for an update or delete call.
*
* @param array $identifiers Input array of columns to values
* @param array $columns List of assigned column names
* @param array $values List of assigned values
*
* @return string[][] a triplet with:
* - the first key being the column names
* - the second key being the values
* - the third key being the criteria strings
*/
private function gatherCriteria(array $identifiers, array $columns = [], array $values = [])
[...]
list($columnList, $paramValues, $criteria) = $this->gatherCriteria($identifier, $columnList, $paramValues); How's that? |
Why do you need |
Because the |
|
Yeah but then you can't destructure can you? Or should I just |
list($columnList, $criteria, $parameterValues) = $this->theFunction(...);
$columns = array_merge($previouslyDefinedColumns, $columnList);
$filter = array_merge($previouslyDefinedCriteria, $criteria); |
If you pass a null to the where array of update or delete it's pretty obvious what you want. Most (all?) databases won't match anything if you actually try to compare with NULL making this a silent failure without it.
Done. Though looking at it the variables in Edit: You know what, never mind. If we start nitpicking variable naming we'll be here another 3 months! |
@jnvsor very good improvement! The last bit to improve is to avoid overwriting variables at all, and then we're done. This bit specifically: $columnList = array_merge($columnList, $whereColumns);
$paramValues = array_merge($paramValues, $whereValues); Indeed, a variable rename is needed |
Added a variable rename and stopped the overwriting |
@jnvsor awesome! Waiting for travis and then this can be merged :-) |
🚢 |
Thanks @jnvsor! |
IS NULL
checking in Connection#delete()
and Connection#update()
generated criteria, allowing for null
column searches
If you pass a null to the where array of update or delete it's
pretty obvious what you want.
Most (all?) databases won't match anything if you actually try
to compare with NULL making this a silent failure without it.