module Sequel::Plugins::AssociationPks::ClassMethods

Private Instance Methods

def_association_pks_methods(opts) click to toggle source

Define a association_pks method using the block for the association reflection

# File lib/sequel/plugins/association_pks.rb, line 61
def def_association_pks_methods(opts)
  association_module_def(:"#{singularize(opts[:name])}_pks", opts){_association_pks_getter(opts)}
  association_module_def(:"#{singularize(opts[:name])}_pks=", opts){|pks| _association_pks_setter(opts, pks)} if opts[:pks_setter]
end
def_many_to_many(opts) click to toggle source

Add a getter that checks the join table for matching records and a setter that deletes from or inserts into the join table.

Calls superclass method
# File lib/sequel/plugins/association_pks.rb, line 68
def def_many_to_many(opts)
  super

  return if opts[:type] == :one_through_one

  # Grab values from the reflection so that the hash lookup only needs to be
  # done once instead of inside every method call.
  lk, lpk, rk = opts.values_at(:left_key, :left_primary_key, :right_key)
  clpk = lpk.is_a?(Array)
  crk = rk.is_a?(Array)

  opts[:pks_getter] = if join_associated_table = opts[:association_pks_use_associated_table]
    tname = opts[:join_table]
    lambda do
      cond = if clpk
        lk.zip(lpk).map{|k, pk| [Sequel.qualify(tname, k), get_column_value(pk)]}
      else
        {Sequel.qualify(tname, lk) => get_column_value(lpk)}
      end
      rpk = opts.associated_class.primary_key
      opts.associated_dataset.
        naked.where(cond).
        select_map(Sequel.public_send(rpk.is_a?(Array) ? :deep_qualify : :qualify, opts.associated_class.table_name, rpk))
    end
  elsif clpk
    lambda do
      cond = lk.zip(lpk).map{|k, pk| [k, get_column_value(pk)]}
      _join_table_dataset(opts).where(cond).select_map(rk)
    end
  else
    lambda do
      _join_table_dataset(opts).where(lk=>get_column_value(lpk)).select_map(rk)
    end
  end

  if !opts[:read_only] && !join_associated_table
    opts[:pks_setter] = lambda do |pks|
      if pks.empty?
        public_send(opts[:remove_all_method])
      else
        checked_transaction do
          if clpk
            lpkv = lpk.map{|k| get_column_value(k)}
            cond = lk.zip(lpkv)
          else
            lpkv = get_column_value(lpk)
            cond = {lk=>lpkv}
          end
          ds = _join_table_dataset(opts).where(cond)
          ds.exclude(rk=>pks).delete
          pks -= ds.select_map(rk)
          lpkv = Array(lpkv)
          key_array = crk ? pks.map{|pk| lpkv + pk} : pks.map{|pk| lpkv + [pk]}
          key_columns = Array(lk) + Array(rk)
          ds.import(key_columns, key_array)
        end
      end
    end
  end

  def_association_pks_methods(opts)
end
def_one_to_many(opts) click to toggle source

Add a getter that checks the association dataset and a setter that updates the associated table.

Calls superclass method
# File lib/sequel/plugins/association_pks.rb, line 133
def def_one_to_many(opts)
  super

  return if opts[:type] == :one_to_one

  key = opts[:key]

  opts[:pks_getter] = lambda do
    public_send(opts[:dataset_method]).select_map(opts.associated_class.primary_key)
  end

  unless opts[:read_only]
    opts[:pks_setter] = lambda do |pks|
      if pks.empty?
        public_send(opts[:remove_all_method])
      else
        primary_key = opts.associated_class.primary_key
        pkh = {primary_key=>pks}

        if key.is_a?(Array)
          h = {}
          nh = {}
          key.zip(pk).each do|k, v|
            h[k] = v
            nh[k] = nil
          end
        else
          h = {key=>pk}
          nh = {key=>nil}
        end

        checked_transaction do
          ds = public_send(opts.dataset_method)
          ds.unfiltered.where(pkh).update(h)
          ds.exclude(pkh).update(nh)
        end
      end
    end
  end

  def_association_pks_methods(opts)
end