Module: ChronoModel::TimeMachine::HistoryModel
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/chrono_model/time_machine/history_model.rb
Defined Under Namespace
Modules: ClassMethods
Instance Method Summary collapse
- #_find_record(options) ⇒ Object
-
#as_of_time ⇒ Time?
Computes an
as_of_timestrictly inside this record's validity period for historical queries. -
#current_version ⇒ Object
Returns this history entry's current record.
-
#first ⇒ Object
Returns the first history entry.
- #historical? ⇒ Boolean
-
#id ⇒ Object
The history id is
hid, but this cannot set as primary key or temporal associations will break. -
#last ⇒ Object
Returns the last history entry.
-
#pred ⇒ Object
Returns the previous history entry, or nil if this is the first one.
-
#read_attribute(attr_name, &block) ⇒ Object
.read_attributeuses the memoizedprimary_keyif it detects that the attribute name isid. -
#rid ⇒ Object
Referenced record ID.
- #save ⇒ Object
- #save! ⇒ Object
-
#succ ⇒ Object
(also: #next)
Returns the next history entry, or nil if this is the last one.
- #update_columns ⇒ Object
-
#valid_from ⇒ Object
Return
nilinstead of -Infinity/Infinity to preserve current Chronomodel behaviour and avoid failures with Rails 7.0 and unbounded time ranges. - #valid_to ⇒ Object
Instance Method Details
#_find_record(options) ⇒ Object
14 15 16 17 18 19 20 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 14 def _find_record() if && [:lock] self.class.preload(strict_loaded_associations).lock([:lock]).find_by!(hid: hid) else self.class.preload(strict_loaded_associations).find_by!(hid: hid) end end |
#as_of_time ⇒ Time?
Computes an as_of_time strictly inside this record's validity period
for historical queries.
Ensures association queries return versions that existed during this
record's validity, not ones that became valid exactly at the boundary
time. When objects are updated in the same transaction, they can share
the same valid_to, which would otherwise cause boundary
mis-selection.
PostgreSQL ranges are half-open [start, end) by default.
243 244 245 246 247 248 249 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 243 def as_of_time if valid_to.is_a?(Time) valid_to - ChronoModel::VALIDITY_TSRANGE_PRECISION else valid_to end end |
#current_version ⇒ Object
Returns this history entry's current record
206 207 208 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 206 def current_version self.class.superclass.find(rid) end |
#first ⇒ Object
Returns the first history entry
194 195 196 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 194 def first self.class.where(id: rid).chronological.first end |
#historical? ⇒ Boolean
161 162 163 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 161 def historical? true end |
#id ⇒ Object
The history id is hid, but this cannot set as primary key
or temporal associations will break. Solutions are welcome.
139 140 141 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 139 def id hid end |
#last ⇒ Object
Returns the last history entry
200 201 202 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 200 def last self.class.where(id: rid).chronological.last end |
#pred ⇒ Object
Returns the previous history entry, or nil if this is the first one.
168 169 170 171 172 173 174 175 176 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 168 def pred return if valid_from.nil? if self.class.timeline_associations.empty? self.class.where('id = ? AND upper(validity) = ?', rid, valid_from).first else super(id: rid, before: valid_from, table: self.class.superclass.quoted_table_name) end end |
#read_attribute(attr_name, &block) ⇒ Object
.read_attribute uses the memoized primary_key if it detects
that the attribute name is id.
Since the primary key may have been changed to hid because of
.find overload, the new behavior may break relations where id is
still the correct attribute to read
Ref: ifad/chronomodel#181
259 260 261 262 263 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 259 def read_attribute(attr_name, &block) return super unless attr_name.to_s == 'id' && @primary_key.to_s == 'hid' _read_attribute('id', &block) end |
#rid ⇒ Object
Referenced record ID.
145 146 147 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 145 def rid attributes[self.class.primary_key] end |
#save ⇒ Object
149 150 151 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 149 def save(*) with_hid_pkey { super } end |
#save! ⇒ Object
153 154 155 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 153 def save!(*) with_hid_pkey { super } end |
#succ ⇒ Object Also known as: next
Returns the next history entry, or nil if this is the last one.
181 182 183 184 185 186 187 188 189 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 181 def succ return if valid_to.nil? if self.class.timeline_associations.empty? self.class.where('id = ? AND lower(validity) = ?', rid, valid_to).first else super(id: rid, after: valid_to, table: self.class.superclass.quoted_table_name) end end |
#update_columns ⇒ Object
157 158 159 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 157 def update_columns(*) with_hid_pkey { super } end |
#valid_from ⇒ Object
Return nil instead of -Infinity/Infinity to preserve current
Chronomodel behaviour and avoid failures with Rails 7.0 and
unbounded time ranges
Check if begin and end are Time because validity is a tsrange
column, so it is either Time, nil, and in some cases Infinity.
Ref: rails/rails#45099 TODO: consider removing when Rails 7.0 support will be dropped
219 220 221 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 219 def valid_from validity.begin if validity.begin.is_a?(Time) end |
#valid_to ⇒ Object
223 224 225 |
# File 'lib/chrono_model/time_machine/history_model.rb', line 223 def valid_to validity.end if validity.end.is_a?(Time) end |