Skip to content

shioyama/wharel

Repository files navigation

Wharel

Gem Version Build Status

Wharel helps you write concise Arel queries with ActiveRecord using Virtual Rows inspired by Sequel.

Although similar in spirit to gems like Squeel and BabySqueel, which provide sophisticated block-based interfaces for querying with Arel, Wharel is much much smaller. In fact, the core of the gem is only 30 lines long! It uses a single BasicObject as a clean room to evaluate the query block. That's really all there is to it.

For a more detailed explanation of the implementation, see this blog post.

Installation

Add this line to your application's Gemfile:

gem 'wharel', '~> 1.0.0'

And then execute:

$ bundle

Or install it yourself as:

$ gem install wharel

Usage

Suppose we have a model Post:

class Post < ApplicationRecord
  has_many :comments
end

And let's assume our Post has columns title and content.

Now, if we wanted to find all the posts with a title which matched the string "foo" and content which matched the string "bar", we'd have to resort to something like this:

title = Post.arel_table[:title]
content = Post.arel_table[:content]
Post.where(title.matches("foo").and(content.matches("bar")))

With Wharel, you can drop the boilerplate and just use a block:

Post.where { title.matches("foo").and(content.matches("bar")) }

Wharel will map title and content in the block to the appropriate Arel attribute for the column.

Wharel also supports most other query methods, e.g. not:

Post.where.not { title.eq("foo") }

... and order:

Post.order { title.lower }

Wharel also supports select, having, pluck, pick, group and or in the same way.

Now suppose we have another model Comment with a column content, and a Post has_many :comments:

class Post < ApplicationRecord
  has_many :comments
end

class Comment < ApplicationRecord
  belongs_to :post
end

Now we want to find all comments which match the title of the comment's post. With standard Arel, you could do this with:

posts = Post.arel_table
comments = Comment.arel_table
Comment.joins(:post).where(comments[:content].matches(posts[:title]))

Using Wharel, you can pass an argument to blocks to handle this case:

Comment.joins(:post).where { |c| Post.where { |p| c.content.matches(p.title) } }

Much better!

Contributing

Notice something wrong or a feature missing? Post an issue or create a pull request.

License

The gem is available as open source under the terms of the MIT License.