Module: ChronoModel::TimeMachine
- Extended by:
- ActiveSupport::Concern
- Includes:
- Patches::AsOfTimeHolder
- Defined in:
- lib/chrono_model/time_machine.rb,
lib/chrono_model/time_machine/timeline.rb,
lib/chrono_model/time_machine/time_query.rb,
lib/chrono_model/time_machine/history_model.rb
Defined Under Namespace
Modules: ClassMethods, HistoryModel, TimeQuery, Timeline
Class Method Summary collapse
Instance Method Summary collapse
-
#as_of(time) ⇒ Object
Returns a read-only representation of this record as it was
timeago. -
#as_of!(time) ⇒ Object
Returns a read-only representation of this record as it was
timeago. -
#changes_against(ref) ⇒ Object
Returns the differences between this record and an arbitrary reference record.
-
#current_version ⇒ Object
Returns the current history version.
-
#destroy ⇒ Object
Inhibit destroy of historical records.
-
#historical? ⇒ Boolean
Returns a boolean indicating whether this record is an history entry.
-
#history ⇒ Object
Return the complete read-only history of this instance.
-
#last_changes ⇒ Object
Returns the differences between this entry and the previous history one.
-
#pred(options = {}) ⇒ Object
Returns the previous record in the history, or nil if this is the only recorded entry.
-
#pred_timestamp(options = {}) ⇒ Object
Returns the previous timestamp in this record’s timeline.
-
#succ ⇒ Object
This is a current record, so its next instance is always nil.
-
#timeline(options = {}) ⇒ Object
Returns an Array of timestamps for which this instance has an history record.
Methods included from Patches::AsOfTimeHolder
Class Method Details
.define_history_model_for(model) ⇒ Object
53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/chrono_model/time_machine.rb', line 53 def self.define_history_model_for(model) history = Class.new(model) do include ChronoModel::TimeMachine::HistoryModel end model.singleton_class.instance_eval do define_method(:history) { history } end model.const_set :History, history end |
Instance Method Details
#as_of(time) ⇒ Object
Returns a read-only representation of this record as it was time ago. Returns nil if no record is found.
99 100 101 |
# File 'lib/chrono_model/time_machine.rb', line 99 def as_of(time) _as_of(time).first end |
#as_of!(time) ⇒ Object
Returns a read-only representation of this record as it was time ago. Raises ActiveRecord::RecordNotFound if no record is found.
106 107 108 |
# File 'lib/chrono_model/time_machine.rb', line 106 def as_of!(time) _as_of(time).first! end |
#changes_against(ref) ⇒ Object
Returns the differences between this record and an arbitrary reference record. The changes representation is an hash keyed by attribute whose values are arrays containing previous and current attributes values - the same format used by ActiveModel::Dirty.
197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/chrono_model/time_machine.rb', line 197 def changes_against(ref) self.class.attribute_names_for_history_changes.inject({}) do |changes, attr| old, new = ref.public_send(attr), self.public_send(attr) changes.tap do |c| changed = old.respond_to?(:history_eql?) ? !old.history_eql?(new) : old != new c[attr] = [old, new] if changed end end end |
#current_version ⇒ Object
Returns the current history version
180 181 182 |
# File 'lib/chrono_model/time_machine.rb', line 180 def current_version self.historical? ? self.class.find(self.id) : self end |
#destroy ⇒ Object
Inhibit destroy of historical records
140 141 142 143 |
# File 'lib/chrono_model/time_machine.rb', line 140 def destroy raise ActiveRecord::ReadOnlyRecord, 'Cannot delete historical records' if historical? super end |
#historical? ⇒ Boolean
Returns a boolean indicating whether this record is an history entry.
134 135 136 |
# File 'lib/chrono_model/time_machine.rb', line 134 def historical? self.as_of_time.present? end |
#history ⇒ Object
Return the complete read-only history of this instance.
121 122 123 |
# File 'lib/chrono_model/time_machine.rb', line 121 def history self.class.history.chronological.of(self) end |
#last_changes ⇒ Object
Returns the differences between this entry and the previous history one. See: changes_against.
187 188 189 190 |
# File 'lib/chrono_model/time_machine.rb', line 187 def last_changes pred = self.pred changes_against(pred) if pred end |
#pred(options = {}) ⇒ Object
Returns the previous record in the history, or nil if this is the only recorded entry.
148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/chrono_model/time_machine.rb', line 148 def pred( = {}) if self.class.timeline_associations.empty? history.order(Arel.sql('upper(validity) DESC')).offset(1).first else return nil unless (ts = ()) order_clause = Arel.sql %[ LOWER(#{[:table] || self.class.quoted_table_name}."validity") DESC ] self.class.as_of(ts).order(order_clause).find([:id] || id) end end |
#pred_timestamp(options = {}) ⇒ Object
Returns the previous timestamp in this record’s timeline. Includes temporal associations.
163 164 165 166 167 168 169 170 |
# File 'lib/chrono_model/time_machine.rb', line 163 def ( = {}) if historical? [:before] ||= as_of_time timeline(.merge(limit: 1, reverse: true)).first else timeline(.merge(limit: 2, reverse: true)).second end end |
#succ ⇒ Object
This is a current record, so its next instance is always nil.
174 175 176 |
# File 'lib/chrono_model/time_machine.rb', line 174 def succ nil end |
#timeline(options = {}) ⇒ Object
Returns an Array of timestamps for which this instance has an history record. Takes temporal associations into account.
128 129 130 |
# File 'lib/chrono_model/time_machine.rb', line 128 def timeline( = {}) self.class.history.timeline(self, ) end |