Module: ChronoModel::TimeMachine::HistoryModel::ClassMethods

Includes:
TimeQuery, Timeline
Defined in:
lib/chrono_model/time_machine/history_model.rb

Overview

Methods that make up the history interface of the companion History model, automatically built for each Model that includes TimeMachine

Instance Method Summary collapse

Methods included from Timeline

#has_timeline, #quoted_history_fields, #timeline, #timeline_associations, #timeline_associations_from

Instance Method Details

#as_of(time) ⇒ Object

Fetches as of time records.



74
75
76
# File 'lib/chrono_model/time_machine/history_model.rb', line 74

def as_of(time)
  non_history_superclass.from(virtual_table_at(time)).as_of_time!(time)
end

#at(time) ⇒ Object

Fetches history record at the given time



87
88
89
# File 'lib/chrono_model/time_machine/history_model.rb', line 87

def at(time)
  time_query(:at, time).from(quoted_table_name).as_of_time!(time)
end

#findObject



33
34
35
# File 'lib/chrono_model/time_machine/history_model.rb', line 33

def find(*)
  with_hid_pkey { super }
end

#history?Boolean

To identify this class as the History subclass



49
50
51
# File 'lib/chrono_model/time_machine/history_model.rb', line 49

def history?
  true
end

#non_history_superclass(klass = self) ⇒ Object

Getting the correct quoted_table_name can be tricky when STI is involved. If Orange < Fruit, then Orange::History < Fruit::History (see define_inherited_history_model_for). This means that the superclass method returns Fruit::History, which will give us the wrong table name. What we actually want is the superclass of Fruit::History, which is Fruit. So, we use non_history_superclass instead. -npj



60
61
62
63
64
65
66
# File 'lib/chrono_model/time_machine/history_model.rb', line 60

def non_history_superclass(klass = self)
  if klass.superclass.history?
    non_history_superclass(klass.superclass)
  else
    klass.superclass
  end
end

#of(object) ⇒ Object

Fetches the given object history, sorted by history record time by default. Always includes an “as_of_time” column that is either the upper bound of the validity range or now() if history validity is maximum.



102
103
104
# File 'lib/chrono_model/time_machine/history_model.rb', line 102

def of(object)
  where(id: object)
end

#pastObject



44
45
46
# File 'lib/chrono_model/time_machine/history_model.rb', line 44

def past
  time_query(:before, :now).where("NOT upper_inf(#{quoted_table_name}.validity)")
end

#relationObject



68
69
70
# File 'lib/chrono_model/time_machine/history_model.rb', line 68

def relation
  super.as_of_time!(Time.now)
end

#sortedObject

Returns the history sorted by recorded_at



93
94
95
# File 'lib/chrono_model/time_machine/history_model.rb', line 93

def sorted
  all.order(Arel.sql(%[ #{quoted_table_name}."recorded_at" ASC, #{quoted_table_name}."hid" ASC ]))
end

#time_query(match, time, options = {}) ⇒ Object

In the History context, pre-fill the :on options with the validity interval.



39
40
41
42
# File 'lib/chrono_model/time_machine/history_model.rb', line 39

def time_query(match, time, options = {})
  options[:on] ||= :validity
  super
end

#virtual_table_at(time, name = nil) ⇒ Object



78
79
80
81
82
83
# File 'lib/chrono_model/time_machine/history_model.rb', line 78

def virtual_table_at(time, name = nil)
  name = name ? connection.quote_table_name(name) :
    non_history_superclass.quoted_table_name

  "(#{at(time).to_sql}) #{name}"
end

#with_hid_pkey(&block) ⇒ Object

HACK. find() and save() require the real history ID. So we are setting it now and ensuring to reset it to the original one after execution completes. FIXME



24
25
26
27
28
29
30
31
# File 'lib/chrono_model/time_machine/history_model.rb', line 24

def with_hid_pkey(&block)
  old = self.primary_key
  self.primary_key = :hid

  block.call
ensure
  self.primary_key = old
end