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

test for finding by null #420

Merged
merged 1 commit into from
Dec 9, 2014
Merged

test for finding by null #420

merged 1 commit into from
Dec 9, 2014

Conversation

shmax
Copy link
Contributor

@shmax shmax commented Jul 15, 2014

Fix for the following issue:

$author = Author::find(0);
// throws RecordNotFound exception (because count(0) == 1)

$author = Author::find(null);
// does not throw an exception (because count(null) == 0)

@jpfuentes2
Copy link
Owner

I'm not sure I am convinced of the utility of this change. It seems to me that this is a user code error because one should not be searching for records in a RDBMS via a null primary key. I believe the proper behavior is to throw RecordNotFound or perhaps a specific error message on null?

@shmax
Copy link
Contributor Author

shmax commented Jul 15, 2014

I believe the proper behavior is to throw RecordNotFound

That's what I'm doing.

Added a custom exception message for invalid key argument.

I snooped around a bit in the rails code to see what they do. Someone who can read Ruby better than me will have to help, but it looks to me like they just do the standard RecordNotFound exception.

https://github.com/rails/rails/blob/master/activerecord/lib/active_record/core.rb

@shmax
Copy link
Contributor Author

shmax commented Jul 15, 2014

I went poking into their tests, and the plot thickens, a bit:

https://github.com/rails/rails/blob/master/activerecord/test/cases/finder_test.rb

They have a test called "test_find_an_empty_array", which expects an empty array as a result. Strangely, they have another test called "test_find_by_empty_ids" which seems to do the same exact thing.

def test_find_by_empty_ids
    assert_equal [], Post.find([])
end

def test_find_an_empty_array
    assert_equal [], Topic.find([])
end

I don't see any tests for null being passed in, but apparently in at least some cases an empty result set can be returned.

@jpfuentes2
Copy link
Owner

I believe we have the find_by_array equivalent in PHP-AR which returns an empty array. That is not the same behavior as a single $id or null.

@shmax
Copy link
Contributor Author

shmax commented Jul 15, 2014

@jpfuentes2
Is it safe to assume that you have a ruby environment set up? Could you be so kind as to see what happens when you find by null?

@jpfuentes2
Copy link
Owner

Kinda, but I don't have any DB stuff setup. I went from PHP -> Ruby -> Scala so I don't do much Ruby these days either.

@jpfuentes2
Copy link
Owner

I don't think it raises a specific exception. I think RecordNotFound is appropriate behavior here.

@shmax
Copy link
Contributor Author

shmax commented Jul 15, 2014

Groovy. Let me know if anything else seems suspicious.

@@ -1581,19 +1581,23 @@ public static function find(/* $type, $options */)
*/
public static function find_by_pk($values, $options)
{
if(is_null($values)){
Copy link
Owner

Choose a reason for hiding this comment

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

if (expr)
{
}

Copy link
Owner

Choose a reason for hiding this comment

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

Or

if (expr)
     expr

Copy link
Collaborator

Choose a reason for hiding this comment

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

null === $values is faster than is_null($values)

Should we be checking explicit null or empty here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, we could check for empty, but then that will change the existing behavior for passing in "0" and empty array.

@shmax
Copy link
Contributor Author

shmax commented Jul 17, 2014

Rebased on master.

@shmax
Copy link
Contributor Author

shmax commented Jul 17, 2014

By the way, is there anything I can do to help get some of these older PRs up to date, passing tests, etc?

@koenpunt
Copy link
Collaborator

There are these long standing issues: #357 and #356 which list all PR's staged for a new release. I'd wanted to start a 1.1-dev branch for some time now to start merging these PRs. But have not found enough time yet..

@koenpunt
Copy link
Collaborator

Oh well, I just did it: https://github.com/jpfuentes2/php-activerecord/tree/1.1-dev

@shmax
Copy link
Contributor Author

shmax commented Jul 17, 2014

@koenpunt So how can I help?

@koenpunt
Copy link
Collaborator

Review any of the open todo's on #430 and submit a rebased version to the 1.1-dev branch

@koenpunt
Copy link
Collaborator

koenpunt commented Dec 8, 2014

In Ruby a ActiveRecord::RecordNotFound is thrown when using nil:

irb(main):002:0> App.find(nil)
ActiveRecord::RecordNotFound: Couldn't find App without an ID

Same for 0, but does a lookup on the database first:

irb(main):004:0> App.find(0)
  App Load (0.4ms)  SELECT  `apps`.* FROM `apps`  WHERE `apps`.`id` = 0 LIMIT 1
ActiveRecord::RecordNotFound: Couldn't find App with 'id'=0

@jpfuentes2
Copy link
Owner

I'm +1 for this but let's use Rails AR's message: Couldn't find #{Model} without an ID

@@ -1645,6 +1646,11 @@ protected static function get_models_from_cache(array $pks)
*/
public static function find_by_pk($values, $options)
{
if(is_null($values))
{
throw new RecordNotFound("Invalid primary key used (".var_export($values, true).")");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Using var_export here is unnecessary, you can simple use null because you're using is_null for testing.

@shmax
Copy link
Contributor Author

shmax commented Dec 8, 2014

Comments addressed.

@@ -887,7 +887,8 @@ private function update($validate=true)
protected function update_cache()
{
$table = static::table();
if($table->cache_individual_model){
if($table->cache_individual_model)
{
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you revert this change? as it is not related to the actual changes. And because there are other changes pending for this part of the code.

@cvanschalkwijk
Copy link
Collaborator

I think it looks good. +1

@koenpunt
Copy link
Collaborator

koenpunt commented Dec 8, 2014

@shmax can you squash your commits into 1? Thanks

@shmax
Copy link
Contributor Author

shmax commented Dec 9, 2014

Squashed to 1 commit.

@jpfuentes2
Copy link
Owner

👍 thanks! Who wants the honor of merging?


if ($expected == 1)
{
if (!is_array($values))
$values = array($values);

throw new RecordNotFound("Couldn't find $class with ID=" . join(',',$values));
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm still kinda puzzled by this. $expected == 1 so no need to join right? Only because it's converted to an array above.

Copy link
Owner

Choose a reason for hiding this comment

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

Good catch: why is this moved? What effect does it have?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, this isn't my code, and I'm not aware of all the possible cases, but this seems to catch a wide variety of them. Imagine the case where an array with one item in it is passed in. Then count($values) == 1, the force to array doesn't happen, but join still works. If a single scalar value is passed in, count($values) is still 1, it gets forced to array, and the join still works.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, and I probably moved it because line 1678 requires an array, but the operation to guarantee an array was happening inside a logical check. It may be that the move wasn't needed, but I found it more clear to read.

@shmax
Copy link
Contributor Author

shmax commented Dec 9, 2014

Per @koenpunt, consolidated two exceptions.

@koenpunt
Copy link
Collaborator

koenpunt commented Dec 9, 2014

I don't think we should remove the second exception

@shmax
Copy link
Contributor Author

shmax commented Dec 9, 2014

Oh, I see what you mean, one sec...

@shmax
Copy link
Contributor Author

shmax commented Dec 9, 2014

Small rearrangement, re-squashed.

if (!is_array($values))
$values = array($values);

$values = join(',',$values);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Almost there, there is no need to convert values to an array if we're going to join it directly after. Or am I missing something?

if (is_array($values))
    $values = join(',', $values);

@shmax
Copy link
Contributor Author

shmax commented Dec 9, 2014

sgtm

$values = array($values);

throw new RecordNotFound("Couldn't find $class with ID=" . join(',',$values));
throw new RecordNotFound("Couldn't find $class with ID=" . $values);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Final note, please use interpolation for $values as well, instead of concatenation.

@shmax
Copy link
Contributor Author

shmax commented Dec 9, 2014

Okie-doke. At this point I have to get to work, so if there is anything else you will either need to make the change yourself, or wait until I get back.

@koenpunt
Copy link
Collaborator

koenpunt commented Dec 9, 2014

I think this will be just fine, thanks!

koenpunt added a commit that referenced this pull request Dec 9, 2014
@koenpunt koenpunt merged commit 083c446 into jpfuentes2:master Dec 9, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants