class Diffit::Tracker
Attributes
Public Class Methods
Instantiates a Diffit::Tracker
with provided timestamp.
@param timestamp [Time, DateTime, Date, Fixnum] date, time or timestamp. @return [Diffit::Tracker] Diffit::Tracker
# File lib/diffit/tracker.rb, line 12 def initialize(timestamp) if timestamp.respond_to?(:to_datetime) @timestamp = timestamp.to_datetime elsif timestamp.respond_to?(:to_i) @timestamp = Time.at(timestamp.to_i).to_datetime else raise ArgumentError, "#{timestamp.inspect} is not a timestamp!" end @tracked = [] @changes = Diffit::Changes.new(self.timestamp) @fetched = false end
Public Instance Methods
Appends all changes.
@return [Diffit::Tracker] a new instance of Diffit::Tracker
.
# File lib/diffit/tracker.rb, line 63 def all copy = self.clone copy.all! copy end
Appends all changes to ‘self`.
@return [self] self.
# File lib/diffit/tracker.rb, line 72 def all! @changes.cleanup! handle_all.group_by { |row| row[:table_name] }.each do |t, records| @changes.append t.classify, records end self end
Appends provided objects.
@param object [ActiveRecord::Relation, ActiveRecord::Base, Array(ActiveRecord::Base), Array(ActiveRecord::Relation)] @return [Diffit::Tracker] new instance of Diffit::Tracker
.
# File lib/diffit/tracker.rb, line 35 def append(*objects) copy = self.clone copy.append!(*objects) copy end
Appends provided objects to ‘self`.
@param object [ActiveRecord::Relation, ActiveRecord::Base, Array(ActiveRecord::Base), Array(ActiveRecord::Relation)] @return [self] self
# File lib/diffit/tracker.rb, line 45 def append!(*objects) objects.flatten! objects.each do |object| if accepts?(object) @tracked << object else raise ArgumentError, 'Expected ActiveRecord::Base or ActiveRecord::Relation' end end @changes.cleanup! @fetched = false self end
# File lib/diffit/tracker.rb, line 80 def changes return @changes if @fetched @tracked.each do |object| if record?(object) @changes.append object.model_name.name, handle_one(object) elsif relation?(object) model = object.respond_to?(:model) ? object.model : object.class changes = case Diffit.strategy when :join then handle_relation_with_join(object) when :subquery then handle_relation_with_subquery(object) end @changes.append model.name, changes end end @fetched = true @changes.prepare! @changes end
# File lib/diffit/tracker.rb, line 26 def initialize_clone(other) @tracked = Array.new(@tracked) @changes = Diffit::Changes.new(self.timestamp) end
Private Instance Methods
# File lib/diffit/tracker.rb, line 104 def accepts?(object) record?(object) || relation?(object) end
Executes raw SQL query. Uses ActiveRecord::Result, performs typecasting.
@param query [ActiveRecord::Relation, Arel::SelectManager] @return [Array(Hash)] query result
# File lib/diffit/tracker.rb, line 186 def execute_query(query) result = ActiveRecord::Base.connection.select_all(query.to_sql) cols = result.columns.map { |c| c.to_sym } rows = result.cast_values rows.map do |row| hash, i, l = {}, 0, cols.length while i < l hash[cols[i]] = row[i] i += 1 end hash end end
# File lib/diffit/tracker.rb, line 170 def handle_all table = Arel::Table.new(Diffit.table_name) query = table. where(table[:changed_at].gteq(self.timestamp)). order(:table_name, :record_id). project(table[:table_name], table[:record_id], table[:column_name], table[:value], table[:changed_at]) execute_query(query) end
# File lib/diffit/tracker.rb, line 157 def handle_one(record) table = Arel::Table.new(Diffit.table_name) query = table. where(table[:changed_at].gteq(self.timestamp)). where(table[:table_name].eq(record.class.table_name)). where(table[:record_id].eq(record.id)). order(:table_name, :record_id). project(table[:record_id], table[:column_name], table[:value], table[:changed_at]) execute_query(query) end
# File lib/diffit/tracker.rb, line 135 def handle_relation_with_join(relation) table = Arel::Table.new(Diffit.table_name) sanitized = relation.except(:select, :order, :group, :having, :includes) query = sanitized. from(table). where(table[:changed_at].gteq(self.timestamp)). where(table[:table_name].eq(relation.table_name)). select(table[:record_id], table[:column_name], table[:value], table[:changed_at]) if sanitized.where_values.present? || sanitized.joins_values.present? join_cond = Arel::Nodes::On.new(sanitized.arel_table[:id].eq(table[:record_id])) join_arel = Arel::Nodes::InnerJoin.new(sanitized.arel_table, join_cond) query = query.joins(join_arel) end execute_query(query) end
# File lib/diffit/tracker.rb, line 116 def handle_relation_with_subquery(relation) table = Arel::Table.new(Diffit.table_name) sanitized = relation.except(:select, :order, :group, :having, :includes).select(:id) query = table. where(table[:changed_at].gteq(self.timestamp)). where(table[:table_name].eq(relation.table_name)). order(:table_name, :record_id) if sanitized.where_values.present? || sanitized.joins_values.present? query = query.where(table[:record_id].in(Arel.sql(sanitized.to_sql))) end query = query.project(table[:record_id], table[:column_name], table[:value], table[:changed_at]) execute_query(query) end
# File lib/diffit/tracker.rb, line 112 def record?(object) object.is_a?(ActiveRecord::Base) end
# File lib/diffit/tracker.rb, line 108 def relation?(object) object.is_a?(ActiveRecord::Relation) || ActiveRecord::Base.descendants.include?(object) end