https://github.com/fengb/arlj
ActiveRecord Left Join
https://github.com/fengb/arlj
Last synced: about 2 months ago
JSON representation
ActiveRecord Left Join
- Host: GitHub
- URL: https://github.com/fengb/arlj
- Owner: fengb
- License: mit
- Created: 2014-11-26T14:45:36.000Z (over 11 years ago)
- Default Branch: master
- Last Pushed: 2015-03-15T00:19:11.000Z (about 11 years ago)
- Last Synced: 2025-07-03T11:55:34.377Z (11 months ago)
- Language: Ruby
- Homepage:
- Size: 270 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# Arlj - ActiveRecord Left Join [](https://travis-ci.org/fengb/arlj)
Make left joins feel like first-class citizens in ActiveRecord.
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'arlj'
```
And then execute:
$ bundle
Or install it yourself as:
$ gem install arlj
## Usage
Load Arlj into your class:
```ruby
class Parent < ActiveRecord::Base
extend Arlj
end
```
Or extend all of ActiveRecord models:
```ruby
ActiveRecord::Base.extend Arlj
```
Then begin to left join!
```ruby
puts Parent.left_joins(:children).group('records.id').select('COUNT(children.id)').to_sql
=> SELECT COUNT(children.id)
FROM "parents"
LEFT OUTER JOIN "children"
ON "children"."parent_id" = "parents"."id"
GROUP BY records.id
```
`left_joins` is purposely low level for maximum control.
Arlj has an aggregation method that is higher level and generally easier to use:
```ruby
Parent.left_joins_aggregate(:children, 'COUNT(*)').to_sql
=> SELECT "parents".*
FROM "parents"
LEFT OUTER JOIN (SELECT "children"."parent_id"
, COUNT("children"."id") AS children_count
FROM "children"
GROUP BY "children"."parent_id") arlj_aggregate_children
ON arlj_aggregate_children."parent_id" = "parents"."id"
```
Supported aggregation functions are `COUNT()`, `SUM()`, `AVG()`, `MIN()`, and `MAX()`.
The aggregation column has a default name of `{table}_{function}_{column}` which
is easily renamed:
```ruby
Parent.left_joins_aggregate(:children, 'SUM(age)' => 'ekkekkekkekkeptangya').to_sql
=> SELECT "parents".*
FROM "parents"
LEFT OUTER JOIN (SELECT "children"."parent_id"
, SUM("children"."age") AS ekkekkekkekkeptangya
FROM "children"
GROUP BY "children"."parent_id") arlj_aggregate_children
ON arlj_aggregate_children."parent_id" = "parents"."id"
```
Since Arlj uses a sub-select, you can easily chain additional queries:
```ruby
Parent.left_joins_aggregate(:children, 'COUNT(*)').select('children_count').to_sql
=> SELECT children_count
FROM "parents"
LEFT OUTER JOIN (SELECT "children"."parent_id"
, COUNT("children"."id") AS children_count
FROM "children"
GROUP BY "children"."parent_id") arlj_aggregate_children
ON arlj_aggregate_children."parent_id" = "parents"."id"
```
Arlj also supports some basic where clauses:
```ruby
Parent.left_joins_aggregate(:children, 'COUNT(*)', where: {age: 1..5}).to_sql
=> SELECT "parents".*
FROM "parents"
LEFT OUTER JOIN (SELECT "children"."parent_id"
, COUNT("children"."id") AS children_count
FROM "children"
WHERE ("children"."age" BETWEEN 1 AND 5)
GROUP BY "children"."parent_id") arlj_aggregate_children
ON arlj_aggregate_children."parent_id" = "parents"."id"
```
If you prefer, you may also use `arlj` and `arlj_aggregate` instead of
`left_joins` and `left_joins_aggregate` respectively. To prevent potential
naming conflicts, use `Arlj::Base` instead:
```ruby
class Parent < ActiveRecord::Base
extend Arlj::Base
end
```
**Arlj** has an experimental flag that uses the **memoist** gem to memoize the
generated join SQL:
```ruby
Arlj.memoize!
```
This has not been proven to be faster.
## Gotchas
* Since `left_joins_aggregate` uses a sub-select for its aggregation, it can
underperform a better optimized query.
* When `left_joins_aggregate` joins zero records, the aggregate column is NULL.
To operate correctly on these columns, please use `COALESCE(col, 0)`.
## TODO
* `left_joins(nested: :relations)`
* `left_joins_aggregate([...], merge: User.active)`
* `has_and_belongs_to_many`
* `has_many :through =>`
## Contributing
1. Fork it ( https://github.com/fengb/arlj/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request