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

Ensure #second (and others) acts like #first AR finder #13757

Merged
merged 1 commit into from Jan 20, 2014

Conversation

Projects
None yet
6 participants
@terracatta
Contributor

terracatta commented Jan 18, 2014

This PR addresses issue #13743 where the ordinal ActiveSupport Array extentions were not assuming a default order like first was.

As suggested by @dhh this commit brings the famous ordinal Array instance methods defined
in ActiveSupport into ActiveRecord as fully-fledged finders.

These finders ensure a default ascending order of the table's primary key, and utilize the OFFSET SQL verb to locate the user's desired record. If an offset is defined in the query, calling #second adds
to the offset to get the actual desired record.

Example:

    User.all.second

    # Before
    # => 'SELECT  "users".* FROM "users"'

    # After
    # => SELECT  "users".* FROM "users"   ORDER BY "users"."id" ASC LIMIT 1 OFFSET 1'

    User.offset(3).second

    # Before
    # => 'SELECT "users".* FROM "users"  LIMIT -1 OFFSET 3' # sqlite3 gem
    # => 'SELECT "users".* FROM "users"  OFFSET 3' # pg gem
    # => 'SELECT `users`.* FROM `users`  LIMIT 18446744073709551615 OFFSET 3' # mysql2 gem"'

    # After
    # => SELECT  "users".* FROM "users"   ORDER BY "users"."id" ASC LIMIT 1 OFFSET 4'
@dhh

This comment has been minimized.

Show comment
Hide comment
@dhh

dhh Jan 19, 2014

Member

Looking good to me! 👍

Member

dhh commented Jan 19, 2014

Looking good to me! 👍

@josevalim

View changes

Show outdated Hide outdated activerecord/lib/active_record/relation/finder_methods.rb
@terracatta

This comment has been minimized.

Show comment
Hide comment
@terracatta

terracatta Jan 19, 2014

Contributor

@josevalim Ok, fixed that up for you! Any other concerns?

Contributor

terracatta commented Jan 19, 2014

@josevalim Ok, fixed that up for you! Any other concerns?

The famous ordinal Array instance methods defined in ActiveSupport
(`first`, `second`, `third`, `fourth`, and `fifth`) are now available as
full-fledged finders in ActiveRecord. The biggest benefit of this is ordering
of the records returned now defaults to the table's primary key in ascending order.

This comment has been minimized.

@senny

senny Jan 20, 2014

Member

Can you add:

Fixes #13743.
@senny

senny Jan 20, 2014

Member

Can you add:

Fixes #13743.

This comment has been minimized.

@terracatta

terracatta Jan 20, 2014

Contributor

Added it after the examples! Thanks for the heads up!

@terracatta

terracatta Jan 20, 2014

Contributor

Added it after the examples! Thanks for the heads up!

@senny

This comment has been minimized.

Show comment
Hide comment
@senny

senny Jan 20, 2014

Member

@terracatta this looks good. Can you squash your commits?

Member

senny commented Jan 20, 2014

@terracatta this looks good. Can you squash your commits?

@carlosantoniodasilva

View changes

Show outdated Hide outdated activerecord/lib/active_record/relation/finder_methods.rb
@rafaelfranca

View changes

Show outdated Hide outdated activerecord/lib/active_record/relation/finder_methods.rb
@terracatta

This comment has been minimized.

Show comment
Hide comment
@terracatta

terracatta Jan 20, 2014

Contributor

@rafaelfranca @carlosantoniodasilva @senny, commits are squashed, updated the changelog, fixed the caching issue by dynamically setting and manually memoizing the instance variable based on the offset passed in. Tested it again on several personal rails projects and the test suite looks good!

Any other feedback?

Contributor

terracatta commented Jan 20, 2014

@rafaelfranca @carlosantoniodasilva @senny, commits are squashed, updated the changelog, fixed the caching issue by dynamically setting and manually memoizing the instance variable based on the offset passed in. Tested it again on several personal rails projects and the test suite looks good!

Any other feedback?

@rafaelfranca

View changes

Show outdated Hide outdated activerecord/lib/active_record/relation/finder_methods.rb
@rafaelfranca

View changes

Show outdated Hide outdated activerecord/CHANGELOG.md
@rafaelfranca

View changes

Show outdated Hide outdated activerecord/lib/active_record/relation/finder_methods.rb
@terracatta

This comment has been minimized.

Show comment
Hide comment
@terracatta

terracatta Jan 20, 2014

Contributor

@rafaelfranca, I made the requested changes, but couldn't reproduce your issue or create a failing test case (still trying), can you try again with the latest code and see if you still get a negative limit?

Contributor

terracatta commented Jan 20, 2014

@rafaelfranca, I made the requested changes, but couldn't reproduce your issue or create a failing test case (still trying), can you try again with the latest code and see if you still get a negative limit?

Ensure #second acts like #first AR finder
This commit bring the famous ordinal Array instance methods defined
in ActiveSupport into ActiveRecord as fully-fledged finders.

These finders ensure a default ascending order of the table's primary
key, and utilize the OFFSET SQL verb to locate the user's desired
record. If an offset is defined in the query, calling #second adds
to the offset to get the actual desired record.

Fixes #13743.
@terracatta

This comment has been minimized.

Show comment
Hide comment
@terracatta

terracatta Jan 20, 2014

Contributor

@rafaelfranca Ok great, added better before examples for pg, sqlite3, and mysql2 gems. I also added some extra test cases for the offset functionality just in case!

Anything else? Sorry for all the back and forth!

Contributor

terracatta commented Jan 20, 2014

@rafaelfranca Ok great, added better before examples for pg, sqlite3, and mysql2 gems. I also added some extra test cases for the offset functionality just in case!

Anything else? Sorry for all the back and forth!

@rafaelfranca

This comment has been minimized.

Show comment
Hide comment
@rafaelfranca

rafaelfranca Jan 20, 2014

Member

Looks good. Thank you so much for working on this.

Member

rafaelfranca commented Jan 20, 2014

Looks good. Thank you so much for working on this.

rafaelfranca added a commit that referenced this pull request Jan 20, 2014

Merge pull request #13757 from terracatta/master
Ensure #second (and others) acts like #first AR finder
@rafaelfranca

This comment has been minimized.

Show comment
Hide comment
@rafaelfranca

rafaelfranca Jan 20, 2014

Member

Merged ❤️

Member

rafaelfranca commented Jan 20, 2014

Merged ❤️

@rafaelfranca rafaelfranca merged commit cafe31a into rails:master Jan 20, 2014

1 check passed

default The Travis CI build passed
Details
@@ -364,19 +444,19 @@ def find_take
end
end
def find_first
def find_nth(offset)
if loaded?
@records.first

This comment has been minimized.

@carlosantoniodasilva

carlosantoniodasilva Jan 21, 2014

Member

This is apparently not going to work with already loaded associations. Just testing around I got two different issues:

# consider the models `Author` has many `Post`s

## 1st scenario - raises exception
>> carlos.posts.reload.first
  Post Load (0.1ms)  SELECT "posts".* FROM "posts"  WHERE "posts"."author_id" = ?  [["author_id", 1]]
=> #<Post id: 1, author_id: 1, title: "ZOMG", body: nil, created_at: "2014-01-21 11:44:22", updated_at: "2014-01-21 11:44:22">
>> carlos.posts.reload.second
  Post Load (0.1ms)  SELECT "posts".* FROM "posts"  WHERE "posts"."author_id" = ?  [["author_id", 1]]
NoMethodError: undefined method 'first' for nil:NilClass
  from....rails/rails/activerecord/lib/active_record/relation/finder_methods.rb:449:in 'find_nth'


## 2nd scenario - returns the same record
>> carlos.posts.first
=> #<Post id: 1, author_id: 1, title: "ZOMG", body: nil, created_at: "2014-01-21 11:44:22", updated_at: "2014-01-21 11:44:22">
>> carlos.posts.second
=> #<Post id: 1, author_id: 1, title: "ZOMG", body: nil, created_at: "2014-01-21 11:44:22", updated_at: "2014-01-21 11:44:22">
>> carlos.posts.third
=> #<Post id: 1, author_id: 1, title: "ZOMG", body: nil, created_at: "2014-01-21 11:44:22", updated_at: "2014-01-21 11:44:22">

@terracatta can you take a look please? It'd be good to provide some tests for already loaded associations with some of these methods. Thanks.

@carlosantoniodasilva

carlosantoniodasilva Jan 21, 2014

Member

This is apparently not going to work with already loaded associations. Just testing around I got two different issues:

# consider the models `Author` has many `Post`s

## 1st scenario - raises exception
>> carlos.posts.reload.first
  Post Load (0.1ms)  SELECT "posts".* FROM "posts"  WHERE "posts"."author_id" = ?  [["author_id", 1]]
=> #<Post id: 1, author_id: 1, title: "ZOMG", body: nil, created_at: "2014-01-21 11:44:22", updated_at: "2014-01-21 11:44:22">
>> carlos.posts.reload.second
  Post Load (0.1ms)  SELECT "posts".* FROM "posts"  WHERE "posts"."author_id" = ?  [["author_id", 1]]
NoMethodError: undefined method 'first' for nil:NilClass
  from....rails/rails/activerecord/lib/active_record/relation/finder_methods.rb:449:in 'find_nth'


## 2nd scenario - returns the same record
>> carlos.posts.first
=> #<Post id: 1, author_id: 1, title: "ZOMG", body: nil, created_at: "2014-01-21 11:44:22", updated_at: "2014-01-21 11:44:22">
>> carlos.posts.second
=> #<Post id: 1, author_id: 1, title: "ZOMG", body: nil, created_at: "2014-01-21 11:44:22", updated_at: "2014-01-21 11:44:22">
>> carlos.posts.third
=> #<Post id: 1, author_id: 1, title: "ZOMG", body: nil, created_at: "2014-01-21 11:44:22", updated_at: "2014-01-21 11:44:22">

@terracatta can you take a look please? It'd be good to provide some tests for already loaded associations with some of these methods. Thanks.

This comment has been minimized.

@terracatta

terracatta Jan 21, 2014

Contributor

Absolutely! Thanks for testing!

@terracatta

terracatta Jan 21, 2014

Contributor

Absolutely! Thanks for testing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment