class Hayfork::UpdateSql
Attributes
bindings[R]
haystack[R]
relation[R]
Public Class Methods
new(haystack, relation, bindings)
click to toggle source
# File lib/hayfork/update_sql.rb, line 8 def initialize(haystack, relation, bindings) @haystack = haystack @relation = relation @bindings = bindings end
Public Instance Methods
model()
click to toggle source
# File lib/hayfork/update_sql.rb, line 26 def model relation.model end
to_sql()
click to toggle source
# File lib/hayfork/update_sql.rb, line 14 def to_sql sql = values_to_check_on_update.map { |field| "OLD.#{field} IS DISTINCT FROM NEW.#{field}" }.join(" OR ") <<-SQL IF #{sql} THEN #{delete.to_sql.strip} #{insert.to_sql.strip} END IF; SQL end
Also aliased as: to_s
values_to_check_on_update()
click to toggle source
# File lib/hayfork/update_sql.rb, line 30 def values_to_check_on_update foreign_keys_by_table_name = {} (relation.joins_values + relation.left_outer_joins_values).each do |join_value| if join_value.is_a? String fail NotImplementedError, "Unhandled literal join: #{join_value.inspect}" end reflection = reflection_for(join_value) table_name = reflection.table_name reflection = reflection.through_reflection if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection) case reflection when ActiveRecord::Reflection::BelongsToReflection foreign_keys_by_table_name[table_name] = [ reflection.foreign_key.to_s ] when ActiveRecord::Reflection::HasManyReflection foreign_keys_by_table_name[table_name] = [] # assume identity keys won't change when ActiveRecord::Reflection::HasAndBelongsToManyReflection foreign_keys_by_table_name[reflection.join_table] = [] # assume identity keys won't change foreign_keys_by_table_name[table_name] = [] # assume identity keys won't change else fail NotImplementedError, "Unhandled reflection: #{reflection.class} (join_value: #{join_value.inspect})" end end values_being_written = bindings.pluck(:raw_value) + predicate_fields values_to_check_on_update = Set.new values_being_written.each do |value| next if value.is_a?(String) # constant if value.relation.name == relation.table_name values_to_check_on_update << value.name.to_s else # The value isn't a field of the current record but of a joined record. # That record hasn't changed so we don't care about its value; but we # do care whether this record's foreign keys have changed (which would # cause it to be associated with a different joined record). values_to_check_on_update.merge foreign_keys_by_table_name.fetch(value.relation.name) end end values_to_check_on_update - model.readonly_attributes end
Private Instance Methods
delete()
click to toggle source
# File lib/hayfork/update_sql.rb, line 80 def delete DeleteSql.new(haystack, relation, bindings) end
field_from_predicate(predicate)
click to toggle source
# File lib/hayfork/update_sql.rb, line 88 def field_from_predicate(predicate) case predicate when Arel::Nodes::Between, Arel::Nodes::Equality, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual, Arel::Nodes::In, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::NotEqual, Arel::Nodes::NotIn field_from_predicate(predicate.left) when Arel::Attributes::Attribute predicate else fail NotImplementedError, "Unhandled predicate: #{predicate.class}: #{predicate.inspect}" end end
insert()
click to toggle source
# File lib/hayfork/update_sql.rb, line 76 def insert InsertSql.new(haystack, relation, bindings) end
predicate_fields()
click to toggle source
# File lib/hayfork/update_sql.rb, line 84 def predicate_fields relation.where_clause.send(:predicates).map(&method(:field_from_predicate)) end
reflection_for(association)
click to toggle source
# File lib/hayfork/update_sql.rb, line 107 def reflection_for(association) Hayfork.reflection_for(model, association) end