Class: Hayfork::UpdateSql
- Inherits:
-
Object
- Object
- Hayfork::UpdateSql
- Defined in:
- lib/hayfork/update_sql.rb
Instance Attribute Summary collapse
-
#bindings ⇒ Object
readonly
Returns the value of attribute bindings.
-
#haystack ⇒ Object
readonly
Returns the value of attribute haystack.
-
#relation ⇒ Object
readonly
Returns the value of attribute relation.
Instance Method Summary collapse
-
#initialize(haystack, relation, bindings) ⇒ UpdateSql
constructor
A new instance of UpdateSql.
- #model ⇒ Object
- #to_sql ⇒ Object (also: #to_s)
- #values_to_check_on_update ⇒ Object
Constructor Details
#initialize(haystack, relation, bindings) ⇒ UpdateSql
8 9 10 11 12 |
# File 'lib/hayfork/update_sql.rb', line 8 def initialize(haystack, relation, bindings) @haystack = haystack @relation = relation @bindings = bindings end |
Instance Attribute Details
#bindings ⇒ Object (readonly)
Returns the value of attribute bindings.
6 7 8 |
# File 'lib/hayfork/update_sql.rb', line 6 def bindings @bindings end |
#haystack ⇒ Object (readonly)
Returns the value of attribute haystack.
6 7 8 |
# File 'lib/hayfork/update_sql.rb', line 6 def haystack @haystack end |
#relation ⇒ Object (readonly)
Returns the value of attribute relation.
6 7 8 |
# File 'lib/hayfork/update_sql.rb', line 6 def relation @relation end |
Instance Method Details
#model ⇒ Object
26 27 28 |
# File 'lib/hayfork/update_sql.rb', line 26 def model relation.model end |
#to_sql ⇒ Object Also known as: to_s
14 15 16 17 18 19 20 21 22 23 |
# 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 |
#values_to_check_on_update ⇒ Object
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# 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 |