Skip to content

Instantly share code, notes, and snippets.

@rzane
Last active July 18, 2020 13:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rzane/8104af09369fbce3d2776c4a194e1de6 to your computer and use it in GitHub Desktop.
Save rzane/8104af09369fbce3d2776c4a194e1de6 to your computer and use it in GitHub Desktop.
QueryExtensions

QueryExtensions

First, you'll need to incorporate the extension:

class ApplicationRecord < ActiveRecord::Base
  extend QueryExtensions
end

Now, you can use it like this:

class Author < ApplicationRecord
end

Author.where_has { age.eq(29).or(age.gt(40)) }
# SELECT "authors".* FROM "authors" WHERE ("authors"."age" = 29 OR "authors"."age" > 40)

Author.joins(:posts).where_has { Post[:title].matches("Breaking News:%") }
# SELECT "authors".* FROM "authors" INNER JOIN "posts" ON "posts"."author_id" = "authors"."id" WHERE "posts"."title" LIKE 'Breaking News:%'

In the example above, age and Post[:title] are instances of Arel::Attributes::Attribute.

module QueryExtensions
def [](name)
arel_table[name]
end
def where_has(&block)
where DSL.new(self).evaluate(&block)
end
def selecting(&block)
select DSL.new(self).evaluate(&block)
end
def ordering(&block)
order DSL.new(self).evaluate(&block)
end
class DSL
def initialize(model)
@model = model
end
def evaluate(&block)
if block.arity.zero?
instance_eval(&block)
else
instance_exec(self, &block)
end
end
private
def respond_to_missing?(name, *)
@model.column_names.include?(name.to_s) || super
end
def method_missing(name, *args, &block)
if @model.column_names.include?(name.to_s)
@model.arel_table[name]
else
super
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment