module ActsAsScd::BaseClassMethods

Public Instance Methods

acts_as_scd(*args) click to toggle source
# File lib/acts_as_scd/base_class_methods.rb, line 6
def acts_as_scd(*args)
  @slowly_changing_columns ||= []
  @slowly_changing_indices ||= []
  @slowly_changing_columns += [[IDENTITY_COLUMN, args], [START_COLUMN, [:integer, :default=>START_OF_TIME]], [END_COLUMN, [:integer, :default=>END_OF_TIME]]]
  @slowly_changing_indices += [IDENTITY_COLUMN, START_COLUMN, END_COLUMN, [START_COLUMN, END_COLUMN]]
  include ActsAsScd
end
belongs_to_identity(assoc, options={}) click to toggle source

Association to be used in a child which belongs to a parent which has identity (the identity is used for the association rather than the id). The inverse assocation should be has_many_through_identity.

# File lib/acts_as_scd/base_class_methods.rb, line 28
def belongs_to_identity(assoc, options={})
  other_model = assoc.to_s.camelize.constantize
  fk = :"#{other_model.model_name.to_s.underscore}_identity"
  if defined?(@slowly_changing_columns)
    @slowly_changing_columns << [fk, other_model.identity_column_definition.last]
    @slowly_changing_indices << fk
  end
  if ActiveRecord::VERSION::MAJOR > 3
    belongs_to assoc, ->{ where "#{other_model.effective_to_column_sql()}=#{END_OF_TIME}" },
               options.reverse_merge(foreign_key: fk, primary_key: IDENTITY_COLUMN)
  else
    belongs_to assoc, options.reverse_merge(
                        foreign_key: fk, primary_key: IDENTITY_COLUMN,
                        conditions: "#{other_model.effective_to_column_sql()}=#{END_OF_TIME}"
                      )
  end
  define_method :"#{assoc}_at" do |date=nil|
    other_model.at(date).where(IDENTITY_COLUMN=>send(fk)).first
  end
end
has_identity(*args) click to toggle source
# File lib/acts_as_scd/base_class_methods.rb, line 14
def has_identity(*args)
  acts_as_scd *args
  if defined?(ModalFields) && respond_to?(:fields)
    fields do
      identity *args
      effective_from :integer, :default=>START_OF_TIME
      effective_to :integer, :default=>END_OF_TIME
    end
  end
end
has_many_identities(assoc, options) click to toggle source

Association to be used in a parent class which has children which have identities (the parent class is referenced by id and may not have identity) The inverse association should be belongs_to

# File lib/acts_as_scd/base_class_methods.rb, line 52
def has_many_identities(assoc, options)
  fk =  options[:foreign_key] || :"#{model_name.to_s.underscore}_id"
  pk = primary_key
  other_model_name = options[:class_name] || assoc.to_s.singularize.camelize
  other_model = other_model_name.to_s.constantize

  # all children iterations
  has_many :"#{assoc}_iterations", class_name: other_model_name, foreign_key: fk

  # current children:
  # has_many assoc, options.merge(conditions: ["#{model.effective_to_column_sql} = :date", :date=>END_OF_TIME)]
  define_method assoc do
    send(:"#{assoc}_iterations").current
  end
  # children at some date
  define_method :"#{assoc}_at" do |date=nil|
    # has_many assoc, options.merge(conditions: [%{#{model.effective_from_column_sql}<=:date AND #{model.effective_to_column_sql}>:date}, :date=>model.effective_date(date)]
    send(:"#{assoc}_iterations").scoped.at(date) # scoped necessary here to avoid delegation to Array
  end

  # all children identities
  define_method :"#{assoc}_identities" do
    # send(:"#{assoc}_iterations").select("DISTINCT #{other_model.identity_column_sql}").order(other_model.identity_column_sql).pluck(:identity)
    # other_model.unscoped.where(fk=>send(pk)).identities
    send(:"#{assoc}_iterations").identities
  end

  # children identities at a date
  define_method :"#{assoc}_identities_at" do |date=nil|
    # send(:"#{assoc}_iterations_at", date).select("DISTINCT #{other_model.identity_column_sql}").order(other_model.identity_column_sql).pluck(:identity)
    # other_model.unscoped.where(fk=>send(pk)).identities_at(date)
    send(:"#{assoc}_iterations").identities_at(date)
  end

  # current children identities
  define_method :"#{assoc}_current_identities" do
    # send(assoc).select("DISTINCT #{other_model.identity_column_sql}").order(other_model.identity_column_sql).pluck(:identity)
    # other_model.unscoped.where(fk=>send(pk)).current_identities
    send(:"#{assoc}_iterations").current_identities
  end

end
scoped() click to toggle source
# File lib/acts_as_scd/base_class_methods.rb, line 99
def scoped
  all
end