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

added ActiveRecord::Relation#left_outer_joins #12071

Merged
merged 1 commit into from
Oct 30, 2015
Merged

Conversation

Crunch09
Copy link
Contributor

Hi,

this adds the ability to use a left outer join query without writing pure SQL as an argument to #joins and also query for a specific selection of columns which doesn't work with #includes.

The ability to do this is already implemented in ActiveRecord::Associations::JoinDependency#build but it was only used with Arel::InnerJoin as join_type.
I am not quite sure about the tests, i just used the InnerJoin tests as a starting point. Any help would be appreciated.

Example:

  User.outer_joins(:posts)
  => SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"

@provideal
Copy link

+1

2 similar comments
@Mario1988
Copy link

+1

@Kleinitay
Copy link

+1

@njakobsen
Copy link
Contributor

+1 @Crunch09 Your patch is so much more pro than my poor man's outer_join where I gsub the inner joins to outer joins. https://gist.github.com/njakobsen/6395146

@egilburg
Copy link
Contributor

+1

@robin850
Copy link
Member

Thanks for your contribution @Crunch09! Actually, it would be awesome if we could update a little bit the guides with this new feature.

@Crunch09
Copy link
Contributor Author

yes, will write something tomorrow

@@ -948,6 +983,11 @@ def build_joins(manager, joins)
end
end

build_join_query(manager, buckets, Arel::InnerJoin)

Copy link
Contributor

Choose a reason for hiding this comment

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

✂️

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thank you, fixed that!

@Vetal4eg
Copy link

Vetal4eg commented Sep 1, 2013

+1

1 similar comment
@csouls
Copy link

csouls commented Sep 1, 2013

+1

@Crunch09
Copy link
Contributor Author

Crunch09 commented Sep 1, 2013

@robin850 Added few sentences in the AR-querying guide about it and also rebased against current master.

@robin850
Copy link
Member

robin850 commented Sep 7, 2013

@Crunch09 : Awesome, thank you! ❤️

@rafaelfranca : Could you please have a look ? It looks awesome to me!

@Crunch09
Copy link
Contributor Author

@rafaelfranca @robin850 I just rebased again against current master, anything more i can do?

@dmathieu
Copy link
Contributor

cc @tenderlove @jonleighton

@toreriklinnerud
Copy link

+1 Outer joins is one of the few remaining things that force us to fall back to SQL in our codebase

build_join_query(manager, buckets, Arel::InnerJoin)
end

def build_join_query(manager, buckets, join_type=nil)
Copy link
Member

Choose a reason for hiding this comment

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

Please do not default join_type to nil. I don't think nil is actually an acceptable value. Change the things that call build_join_query to actually pass in the things it needs.

@tenderlove
Copy link
Member

Can you please change these tests not to use to_sql? We have a capture_sql command that you can use to make assertions against the sql run against the database.

@tenderlove
Copy link
Member

I'm positive on this, but the copy/paste make me uneasy. :(

@@ -937,11 +938,17 @@ This will result in the following SQL:
SELECT clients.* FROM clients LEFT OUTER JOIN addresses ON addresses.client_id = clients.id
```

### Using Array/Hash of Named Associations
Instead of writing raw SQL in this case you could also use the `outer_joins` method
which would produce the same result.
Copy link
Member

Choose a reason for hiding this comment

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

If we're going to introduce an outer_joins, I think this is a bit of an "also-ran" position to mention it... we should probably be offering it before we suggest raw SQL.

In fact, maybe the SQL should change, to show a still-legitimate use case for a raw JOIN, as it previously did, instead of an inferior spelling of built-in functionality.

@matthewd
Copy link
Member

I'm vaguely wary of outer_joins == LEFT OUTER JOIN. With includes, that's abstracted-away implementation detail. But here...

Maybe consider left_joins?

@tenderlove
Copy link
Member

I'm vaguely wary of outer_joins == LEFT OUTER JOIN. With includes, that's abstracted-away implementation detail. But here...

Maybe consider left_joins?

Good point. If it's actually going to do an LOJ, the method should probably be left_joins or left_outer_joins.

@Crunch09
Copy link
Contributor Author

Thank you for your feedback! I'll update this PR over the weekend and report back then

@al2o3cr
Copy link
Contributor

al2o3cr commented Apr 25, 2014

One thing I'd love to see but don't have a clear API for - the ability to specify additional bits in the ON clause. Perhaps something like:

User.outer_joins(:posts) { where(featured: true) }

which would produce the SQL:

SELECT ... FROM users
LEFT OUTER JOIN posts ON posts.user_id = users.id AND posts.featured = 't'

assuming there's a boolean featured column on posts.

Note that the above is not equivalent to:

User.outer_joins(:posts).where(featured: true)

since that query doesn't include users who don't have any featured posts.

Without this feature, it would still be possible to create the desired SQL with a scoped association:

# on User
has_many :featured_posts, -> { where(featured: true) }, class_name: 'Post'

User.outer_joins(:featured_posts)

but that method doesn't exactly scale to arbitrary sets of conditions.

@matthewd
Copy link
Member

@al2o3cr +1. We should probably address that separately, afterwards, though... whatever we end up with seems like it should apply to includes as well. This would address one of the biggest causes of scoped-association proliferation that I see. (:through targets being the other.)

@njakobsen
Copy link
Contributor

Any word on when this will be merged? It's been a long time in coming, and every project I make ends up needing left outer joins.

@Crunch09
Copy link
Contributor Author

it's my fault. There were lots of changes in the affected code and i need to solve the merge conflicts and also apply the feedback. I started with that and i hope i can finish it this weekend, sorry about the long wait.

@Crunch09
Copy link
Contributor Author

@k0kubun Good point! I would be fine either way.
@tenderlove I don't know if you remember, but we talked briefly at Arrrcamp about this 😄 I rebased it against current master, would be great if you could take another look if you have the time 😉

@dmitry
Copy link
Contributor

dmitry commented Feb 25, 2015

@al2o3cr have you already created separate issue for supporting the User.outer_joins(:posts) { where(featured: true) }?

@njakobsen
Copy link
Contributor

Doh. I needed a left outer join again today.

@rails rails locked and limited conversation to collaborators Mar 10, 2015
Example:
  User.left_outer_joins(:posts)
  => SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
@rails rails unlocked this conversation Sep 10, 2015
@sgrif sgrif merged commit 3f46ef1 into rails:master Oct 30, 2015
sgrif added a commit that referenced this pull request Oct 30, 2015
added ActiveRecord::Relation#outer_joins
sgrif added a commit that referenced this pull request Oct 30, 2015
This assumes only one query was ever executed, but it appears to
sometimes be loading schema information. We can just look at the array
of queries, rather than the "first" one that was run
@egilburg
Copy link
Contributor

🎉

@thibaudgg
Copy link
Contributor

👏 👏

@Crunch09
Copy link
Contributor Author

Thank you all ❤️ So happy this got merged!

@Crunch09 Crunch09 deleted the outer_joins branch October 31, 2015 19:46
@njakobsen
Copy link
Contributor

👏👏

@rafaelfranca rafaelfranca modified the milestones: 5.0.0 [temp], 5.0.0 Dec 30, 2015
@prathamesh-sonpatki prathamesh-sonpatki changed the title added ActiveRecord::Relation#outer_joins added ActiveRecord::Relation#left_outer_joins Mar 10, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet