Skip to content

Commit

Permalink
Use arel instead custom SQL
Browse files Browse the repository at this point in the history
  • Loading branch information
camilova committed Aug 9, 2022
1 parent cfb0e29 commit a10eb9e
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 48 deletions.
38 changes: 14 additions & 24 deletions lib/update_by_case.rb
Expand Up @@ -3,6 +3,7 @@
require_relative "update_by_case/version"
require_relative "update_by_case/utils"
require "active_record"
require "byebug" if ENV['ENV']&.downcase == 'development'

module UpdateByCase
extend ::ActiveSupport::Concern
Expand All @@ -12,37 +13,26 @@ module UpdateByCase
class << self

def update_by_case!(cases)
case_sql_fragment = ""
update_hash = {}
cases.each do |attribute_name, attribute_cases|
next if attribute_name&.to_s == Utils::WHERE_OPTION
if attribute_cases.is_a?(Hash) && attribute_cases.size == 1 &&
attribute_cases.first.second.is_a?(Hash) then
case_sql_fragment += Utils.separate_operator unless case_sql_fragment.empty?
case_sql_fragment += Utils.build_case_sql_fragment(
self,
attribute_name,
attribute_cases.first.first,
attribute_cases.first.second,
)
if attribute_cases.is_a?(Hash) && attribute_cases.size == 1 &&
attribute_cases.first&.second&.is_a?(Hash) then
cases = attribute_cases.first.second
key_attribute = attribute_cases.first.first
case_statement = Utils.build_case_statement(self, attribute_name, key_attribute, cases)
elsif attribute_cases.is_a?(Hash) && attribute_cases.size.positive?
case_sql_fragment += Utils.separate_operator unless case_sql_fragment.empty?
case_sql_fragment += Utils.build_case_sql_fragment(
self,
attribute_name,
primary_key,
attribute_cases
)
key_attribute = primary_key
case_statement = Utils.build_case_statement(self, attribute_name, key_attribute, attribute_cases)
elsif ! attribute_cases.is_a?(Hash)
# Assume attribute_cases is only one value for all cases
case_sql_fragment += Utils.separate_operator unless case_sql_fragment.empty?
value = Utils.sql_value(attribute_cases)
sql_type = Utils.sql_type(self, attribute_name)
case_sql_fragment += "#{attribute_name}=#{value}::#{sql_type}#{Utils::SEPARATOR}"
case_statement = attribute_cases
else
raise 'invalid provided cases hash'
end
update_hash[attribute_name] = case_statement
end
instance = self
instance = where(cases[:where]) if cases[:where].present?
instance.update_all(case_sql_fragment)
where(cases[:where] || {}).update_all(update_hash)
end

def update_by_case(cases)
Expand Down
33 changes: 9 additions & 24 deletions lib/update_by_case/utils.rb
@@ -1,34 +1,19 @@
require 'arel'

module UpdateByCase
class Utils
WHERE_OPTION = 'where'.freeze
SEPARATOR = (ENV['ENV']&.downcase == 'development' ? "\n" : " ").freeze

class << self

def separate_operator
",#{SEPARATOR}"
end

def sql_value(attribute_value)
attribute_value.nil?? 'NULL' : "'#{attribute_value}'"
end

def sql_type(model, attribute_name)
model.columns.find { |c| c.name.to_s == attribute_name.to_s }.sql_type
end

def build_case_sql_fragment(model, attribute_name, key_attribute, attribute_cases)
case_sql_fragment = "#{attribute_name}=(CASE #{key_attribute}#{SEPARATOR}"
attribute_cases.each do |key_attribute_value, attribute_value|
value = sql_value(attribute_value)
sql_key_attribute_value = key_attribute_value
if key_attribute_value.is_a?(String) || key_attribute_value.is_a?(Symbol)
sql_key_attribute_value = "'#{key_attribute_value}'"
end
case_sql_fragment += "WHEN #{sql_key_attribute_value} THEN #{value}#{SEPARATOR}"
def build_case_statement(model, attribute_name, key_attribute, cases)
case_statement = Arel::Nodes::Case.new
arel_table = model.arel_table
cases.each do |xcase|
condition = arel_table[key_attribute].eq(xcase.first)
case_statement.when(condition).then(xcase.second)
end
sql_type = sql_type(model, attribute_name)
case_sql_fragment += "ELSE #{attribute_name} END)::#{sql_type}"
case_statement.else(arel_table[attribute_name])
end

end
Expand Down

0 comments on commit a10eb9e

Please sign in to comment.