module Sequel::Plugins::Bitemporal::InstanceMethods
Attributes
pending_version[R]
Public Instance Methods
after_create()
click to toggle source
Calls superclass method
# File lib/sequel/plugins/bitemporal.rb, line 362 def after_create super if @create_version @create_version = nil return false unless save_pending_version end end
after_save()
click to toggle source
Calls superclass method
# File lib/sequel/plugins/bitemporal.rb, line 378 def after_save super _refresh_set_values @values end
attributes()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 316 def attributes if pending_version pending_version.values elsif current_version current_version.values else initial_version.values end end
attributes=(attributes)
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 326 def attributes=(attributes) @pending_version ||= begin current_attributes = if composite_primary_key? version_values else { master_id: id } end current_version.keys.each do |key| next if excluded_columns.include? key current_attributes[key] = current_version.public_send key end if current_version? model.version_class.new current_attributes end pending_version.set_all attributes end
audited?()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 296 def audited? !!self.class.audit_class end
before_create()
click to toggle source
Calls superclass method
# File lib/sequel/plugins/bitemporal.rb, line 357 def before_create @create_version = pending_version_holds_changes? super end
before_update()
click to toggle source
Calls superclass method
# File lib/sequel/plugins/bitemporal.rb, line 370 def before_update if pending_version_holds_changes? expire_previous_versions return false unless save_pending_version end super end
before_validation()
click to toggle source
Calls superclass method
# File lib/sequel/plugins/bitemporal.rb, line 300 def before_validation prepare_pending_version super end
composite_primary_key?()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 383 def composite_primary_key? [*primary_key].size > 1 end
deleted?()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 425 def deleted? !new? && !current_version end
destroy()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 387 def destroy point_in_time = ::Sequel::Plugins::Bitemporal.point_in_time versions_dataset.where( expired_at: nil ).where( Sequel.lit("valid_to>valid_from") ).update expired_at: point_in_time end
destroy_version(version, expand_previous_version)
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 396 def destroy_version(version, expand_previous_version) now = ::Sequel::Plugins::Bitemporal.now point_in_time = ::Sequel::Plugins::Bitemporal.point_in_time return false if version.valid_to.to_datetime<=now associations.delete :current_version model.db.transaction do success = true version_was_valid = now>=version.valid_from.to_datetime if expand_previous_version previous = versions_dataset.where({ expired_at: nil, valid_to: version.valid_from, }).where(Sequel.lit("valid_to>valid_from")).first if previous if version_was_valid success &&= save_fossil previous, created_at: point_in_time, valid_from: now, valid_to: version.valid_to else success &&= save_fossil previous, created_at: point_in_time, valid_to: version.valid_to success &&= previous.update expired_at: point_in_time end end end success &&= save_fossil version, created_at: point_in_time, valid_to: now if version_was_valid success &&= version.update expired_at: point_in_time raise Sequel::Rollback unless success success end end
last_version()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 429 def last_version @last_version ||= begin return if new? t = ::Sequel::Plugins::Bitemporal.point_in_time n = ::Sequel::Plugins::Bitemporal.now if use_ranges = self.class.use_ranges range_conditions = self.class.existence_range_contains t end versions_dataset.where do if use_ranges range_conditions else (created_at <= t) & Sequel.|({expired_at=>nil}, expired_at > t) end & (valid_from <= n) end.order(Sequel.desc(:valid_to), Sequel.desc(:created_at)).first end end
next_version()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 448 def next_version @next_version ||= begin return if new? t = ::Sequel::Plugins::Bitemporal.point_in_time n = ::Sequel::Plugins::Bitemporal.now if use_ranges = self.class.use_ranges range_conditions = self.class.existence_range_contains t end versions_dataset.where do if use_ranges range_conditions else (created_at <= t) & Sequel.|({expired_at=>nil}, expired_at > t) end & (valid_from > n) end.order(Sequel.asc(:valid_to), Sequel.desc(:created_at)).first end end
pending_or_current_version()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 312 def pending_or_current_version pending_version || current_version || initial_version end
propagated_during_last_save()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 490 def propagated_during_last_save @propagated_during_last_save ||= [] end
reload()
click to toggle source
Calls superclass method
# File lib/sequel/plugins/bitemporal.rb, line 482 def reload @last_version = nil @current_version_values = nil @pending_version = nil @initial_version = nil super end
restore(attrs={})
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 467 def restore(attrs={}) return false unless deleted? last_version_attributes = if last_version last_version.columns.each_with_object({}) do |column, hash| unless excluded_columns.include? column hash[column] = last_version.public_send column end end else {} end update_attributes last_version_attributes.merge attrs @last_version = nil end
update_attributes(attributes={})
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 348 def update_attributes(attributes={}) self.attributes = attributes if save raise_on_failure: false self else false end end
validate()
click to toggle source
Calls superclass method
# File lib/sequel/plugins/bitemporal.rb, line 305 def validate super pending_version.errors.each do |key, key_errors| key_errors.each{|error| errors.add key, error} end if pending_version_holds_changes? && !pending_version.valid? end
version_foreign_keys()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 494 def version_foreign_keys composite_primary_key? ? primary_key : :master_id end
version_values()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 344 def version_values version_foreign_keys.map { |k| [k, public_send(k)] }.to_h end
Private Instance Methods
current_version?()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 618 def current_version? !new? && current_version end
excluded_columns()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 654 def excluded_columns self.class.excluded_columns end
excluded_columns_for_changes()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 658 def excluded_columns_for_changes [] end
expire_previous_versions()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 508 def expire_previous_versions master_changes = values.select{|k| changed_columns.include? k} lock! set master_changes expired = versions_dataset.where expired_at: nil expired = expired.exclude Sequel.lit("valid_from=valid_to") expired = expired.exclude Sequel.lit("valid_to<=?", pending_version.valid_from) pending_version.valid_to ||= expired.where(Sequel.lit("valid_from>?", pending_version.valid_from)).min(:valid_from) pending_version.valid_to ||= Time.utc 9999 expired = expired.exclude Sequel.lit("valid_from>=?", pending_version.valid_to) expired = expired.all expired.each do |expired_version| if expired_version.valid_from<pending_version.valid_from && expired_version.valid_to>pending_version.valid_from return false unless save_fossil expired_version, created_at: pending_version.created_at, valid_to: pending_version.valid_from elsif expired_version.valid_from<pending_version.valid_to && expired_version.valid_to>pending_version.valid_to return false unless save_fossil expired_version, created_at: pending_version.created_at, valid_from: pending_version.valid_to end end versions_dataset.where(id: expired.collect(&:id)).update expired_at: pending_version.created_at end
initial_version()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 662 def initial_version @initial_version ||= model.version_class.new end
pending_version_holds_changes?()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 622 def pending_version_holds_changes? return false unless @pending_version return true unless current_version? @current_version_values = values_for_changes current_version values_for_changes(pending_version).any? do |column, new_value| case column when :id, :created_at, :expired_at, *version_foreign_keys false when :valid_from pending_version.values.has_key?(:valid_from) && ( new_value<current_version.valid_from || ( current_version.valid_to && new_value>current_version.valid_to ) ) when :valid_to pending_version.values.has_key?(:valid_to) && new_value!=current_version.valid_to else if model.version_uses_string_nilifier if current_version.respond_to? :nil_string? new_value = nil if current_version.nil_string? column, new_value elsif !model.version_class.skip_input_transformer?(:string_nilifier, column) new_value = model.version_class.input_transformers[:string_nilifier].call(new_value) end end current_version.public_send(column)!=new_value end end end
prepare_pending_version()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 500 def prepare_pending_version return unless pending_version_holds_changes? now = ::Sequel::Plugins::Bitemporal.now point_in_time = ::Sequel::Plugins::Bitemporal.point_in_time pending_version.created_at = point_in_time pending_version.valid_from ||= now end
propagate_changes_to_future_versions()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 529 def propagate_changes_to_future_versions return true unless self.class.propagate_per_column @propagated_during_last_save = [] lock! futures = versions_dataset.where expired_at: nil futures = futures.exclude Sequel.lit("valid_from=valid_to") futures = futures.exclude Sequel.lit("valid_to<=?", pending_version.valid_from) futures = futures.where Sequel.lit("valid_from>?", pending_version.valid_from) futures = futures.order(:valid_from).all to_check_columns = self.class.version_class.columns - excluded_columns updated_by = (send(self.class.audit_updated_by_method) if audited?) previous_values = @current_version_values || {} current_values = values_for_changes pending_version futures.each do |future_version| attrs = {} to_check_columns.each do |col| if previous_values[col]==future_version[col] && previous_values[col]!=current_values[col] attrs[col] = current_values[col] end end if attrs.any? propagated = save_propagated future_version, attrs previous_values = values_for_changes future_version current_values = values_for_changes propagated if !propagated.new? && audited? && updated_by self.class.audit_class.audit( self, previous_values, current_values, propagated.valid_from, updated_by ) end future_version.this.update :expired_at => Sequel::Plugins::Bitemporal.point_in_time else break end end end
save_fossil(expired, attributes={})
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 593 def save_fossil(expired, attributes={}) fossil = model.version_class.new expired_attributes = expired.keys.each_with_object({}) do |key, hash| hash[key] = expired.public_send key end expired_attributes.delete :id fossil.set_all expired_attributes.merge(attributes) fossil.save validate: false fossil.send :_refresh_set_values, fossil.values end
save_pending_version()
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 571 def save_pending_version current_values_for_audit = @current_version_values || {} pending_version.valid_to ||= Time.utc 9999 success = add_version pending_version if success if audited? updated_by = send(self.class.audit_updated_by_method) self.class.audit_class.audit( self, current_values_for_audit, values_for_changes(pending_version), pending_version.valid_from, updated_by ) if updated_by end propagate_changes_to_future_versions @current_version_values = nil @pending_version = nil end success end
save_propagated(version, attributes={})
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 604 def save_propagated(version, attributes={}) propagated = model.version_class.new version_attributes = version.keys.each_with_object({}) do |key, hash| hash[key] = version.public_send key end version_attributes.delete :id version_attributes[:created_at] = Sequel::Plugins::Bitemporal.point_in_time propagated.set_all version_attributes.merge(attributes) propagated.save validate: false propagated.send :_refresh_set_values, propagated.values propagated_during_last_save << propagated propagated end
values_for_changes(version)
click to toggle source
# File lib/sequel/plugins/bitemporal.rb, line 666 def values_for_changes(version) values = {} (version.columns - excluded_columns_for_changes).each do |column| values[column] = version.public_send column end values end