Skip to content

Commit

Permalink
Convert active record queries to ARel
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitry committed Nov 12, 2020
1 parent 960adcc commit da1be70
Showing 1 changed file with 26 additions and 21 deletions.
47 changes: 26 additions & 21 deletions lib/statesman/adapters/active_record_queries.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ def included(base)
query_builder = QueryBuilder.new(base, **@args)

base.define_singleton_method(:most_recent_transition_join) do
query_builder.most_recent_transition_join
query_builder.most_recent_transition_join.to_sql
end

define_in_state(base, query_builder)
define_not_in_state(base, query_builder)
define_in_state(base)
define_not_in_state(base)
end

private
Expand All @@ -62,21 +62,21 @@ def ensure_inheritance(base)
end
end

def define_in_state(base, query_builder)
def define_in_state(base)
base.define_singleton_method(:in_state) do |*states|
states = states.flatten

joins(most_recent_transition_join).
where(query_builder.states_where(states), states)
where(query_builder.in_state_conditions(states))
end
end

def define_not_in_state(base, query_builder)
def define_not_in_state(base)
base.define_singleton_method(:not_in_state) do |*states|
states = states.flatten

joins(most_recent_transition_join).
where("NOT (#{query_builder.states_where(states)})", states)
where(query_builder.in_state_conditions(states).not)
end
end
end
Expand All @@ -92,23 +92,24 @@ def initialize(model, transition_class:, initial_state:,
@transition_name = transition_name
end

def states_where(states)
def most_recent_transition_join
table.
join(transition_table, Arel::Nodes::OuterJoin).
on(transition_table[transition_reflection.foreign_key].eq(table[:id]).
and(transition_table[:most_recent].eq(true))).
join_sources
end

def in_state_conditions(states)
if initial_state.to_s.in?(states.map(&:to_s))
"#{most_recent_transition_alias}.to_state IN (?) OR " \
"#{most_recent_transition_alias}.to_state IS NULL"
transition_table[:to_state].in(states).
or(transition_table[:to_state].eq(nil))
else
"#{most_recent_transition_alias}.to_state IN (?) AND " \
"#{most_recent_transition_alias}.to_state IS NOT NULL"
transition_table[:to_state].in(states).
and(transition_table[:to_state].not_eq(nil))
end
end

def most_recent_transition_join
"LEFT OUTER JOIN #{model_table} AS #{most_recent_transition_alias} " \
"ON #{model.table_name}.id = " \
"#{most_recent_transition_alias}.#{model_foreign_key} " \
"AND #{most_recent_transition_alias}.most_recent = #{db_true}"
end

private

attr_reader :model, :transition_class, :initial_state
Expand Down Expand Up @@ -140,8 +141,12 @@ def most_recent_transition_alias
"most_recent_#{transition_name.to_s.singularize}"
end

def db_true
::ActiveRecord::Base.connection.quote(true)
def transition_table
transition_class.arel_table.alias(most_recent_transition_alias)
end

def table
model.arel_table
end
end
end
Expand Down

0 comments on commit da1be70

Please sign in to comment.