module CompositePrimaryKeys::ActiveRecord::FinderMethods

Public Instance Methods

apply_join_dependency(eager_loading: group_values.empty?) { |relation, join_dependency| ... } click to toggle source
# File lib/composite_primary_keys/relation/finder_methods.rb, line 4
def apply_join_dependency(eager_loading: group_values.empty?)
  join_dependency = construct_join_dependency(eager_load_values + includes_values, Arel::Nodes::OuterJoin)
  relation = except(:includes, :eager_load, :preload).joins!(join_dependency)

  if eager_loading && !using_limitable_reflections?(join_dependency.reflections)
    if has_limit_or_offset?
      limited_ids = limited_ids_for(relation)

      # CPK
      # limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids)
      limited_ids.empty? ? relation.none! : relation.where!(cpk_in_predicate(table, self.primary_keys, limited_ids))
    end
    relation.limit_value = relation.offset_value = nil
  end

  if block_given?
    yield relation, join_dependency
  else
    relation
  end
end
construct_relation_for_exists(conditions) click to toggle source
# File lib/composite_primary_keys/relation/finder_methods.rb, line 50
def construct_relation_for_exists(conditions)
  conditions = sanitize_forbidden_attributes(conditions)

  if distinct_value && offset_value
    relation = except(:order).limit!(1)
  else
    relation = except(:select, :distinct, :order)._select!(::ActiveRecord::FinderMethods::ONE_AS_ONE).limit!(1)
  end

  case conditions
    # CPK
    when CompositePrimaryKeys::CompositeKeys
      relation = relation.where(cpk_id_predicate(table, primary_key, conditions))
    # CPK
    when Array
      pk_length = @klass.primary_keys.length

      if conditions.length == pk_length # E.g. conditions = ['France', 'Paris']
        return self.construct_relation_for_exists(conditions.to_composite_keys)
      else # Assume that conditions contains where relation
        relation = relation.where(conditions)
      end
    when Array, Hash
      relation.where!(conditions) unless conditions.empty?
    else
      relation.where!(primary_key => conditions) unless conditions == :none
  end

  relation
end
find_one(id) click to toggle source

def last(limit = nil)

return find_last(limit) if loaded? || has_limit_or_offset?

result = limit(limit || 1)
# CPK
# result.order!(table[primary_key]) if order_values.empty? && primary_key
if order_values.empty? && primary_key
  if composite?
    result.order!(primary_keys.map { |pk| table[pk].asc })
  elsif
    result.order!(table[primary_key])
  end
end

result = result.reverse_order!

limit ? result.reverse : result.first

rescue ::ActiveRecord::IrreversibleOrderError

ActiveSupport::Deprecation.warn(<<-WARNING.squish)
    Finding a last element by loading the relation when SQL ORDER
    can not be reversed is deprecated.
    Rails 5.1 will raise ActiveRecord::IrreversibleOrderError in this case.
    Please call `to_a.last` if you still want to load the relation.
WARNING
find_last(limit)

end

# File lib/composite_primary_keys/relation/finder_methods.rb, line 135
      def find_one(id)
        if ::ActiveRecord::Base === id
          raise ArgumentError, <<-MSG.squish
            You are passing an instance of ActiveRecord::Base to `find`.
            Please pass the id of the object by calling `.id`.
          MSG
        end

        # CPK
        #relation = where(primary_key => id)
        relation = where(cpk_id_predicate(table, primary_keys, id))
        record = relation.take

        raise_record_not_found_exception!(id, 0, 1) unless record

        record
      end
find_some(ids) click to toggle source
# File lib/composite_primary_keys/relation/finder_methods.rb, line 153
def find_some(ids)
  # CPK
  if composite?
    ids = if ids.length == 1
            CompositePrimaryKeys::CompositeKeys.parse(ids.first)
          else
            ids.to_composite_keys
          end
  end

  return find_some_ordered(ids) unless order_values.present?

  # CPK
  # result = where(primary_key => ids).to_a
  result = if composite?
    result = where(cpk_in_predicate(table, primary_keys, ids)).to_a
  else
    result = where(primary_key => ids).to_a
  end

  expected_size =
    if limit_value && ids.size > limit_value
      limit_value
    else
      ids.size
    end

  # 11 ids with limit 3, offset 9 should give 2 results.
  if offset_value && (ids.size - offset_value < expected_size)
    expected_size = ids.size - offset_value
  end

  if result.size == expected_size
    result
  else
    raise_record_not_found_exception!(ids, result.size, expected_size)
  end
end
find_some_ordered(ids) click to toggle source
# File lib/composite_primary_keys/relation/finder_methods.rb, line 192
def find_some_ordered(ids)
  ids = ids.slice(offset_value || 0, limit_value || ids.size) || []

  # CPK
  # result = except(:limit, :offset).where(primary_key => ids).records
  result = if composite?
    except(:limit, :offset).where(cpk_in_predicate(table, primary_keys, ids)).records
  else
    except(:limit, :offset).where(primary_key => ids).records
  end

  if result.size == ids.size
    pk_type = @klass.type_for_attribute(primary_key)

    records_by_id = result.index_by(&:id)
    # CPK
    # ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
    if composite?
      ids.map do |id|
        typecasted_id = primary_keys.zip(id).map do |col, val|
          @klass.type_for_attribute(col).cast(val)
        end
        records_by_id.fetch(typecasted_id)
      end
    else
      ids.map { |id| records_by_id.fetch(pk_type.cast(id)) }
    end
  else
    raise_record_not_found_exception!(ids, result.size, ids.size)
  end
end
find_with_ids(*ids) click to toggle source
# File lib/composite_primary_keys/relation/finder_methods.rb, line 81
def find_with_ids(*ids)
  raise UnknownPrimaryKey.new(@klass) if primary_key.nil?

  # CPK
  # expects_array = ids.first.kind_of?(Array)
  ids = CompositePrimaryKeys.normalize(ids, @klass.primary_keys.length)
  expects_array = ids.flatten != ids.flatten(1)
  return ids.first if expects_array && ids.first.empty?

  # CPK
  # ids = ids.flatten.compact.uniq
  ids = expects_array ? ids.first : ids

  model_name = @klass.name

  case ids.size
  when 0
    error_message = "Couldn't find #{model_name} without an ID"
    raise ::ActiveRecord::RecordNotFound.new(error_message, model_name, primary_key)
  when 1
    result = find_one(ids.first)
    expects_array ? [ result ] : result
  else
    find_some(ids)
  end
end
limited_ids_for(relation) click to toggle source
# File lib/composite_primary_keys/relation/finder_methods.rb, line 26
def limited_ids_for(relation)
  # CPK
  # values = @klass.connection.columns_for_distinct(
  #     connection.column_name_from_arel_node(table[primary_key]),
  #     relation.order_values
  # )

  columns = @klass.primary_keys.map do |key|
    connection.visitor.compile(table[key])
  end
  values = @klass.connection.columns_for_distinct(columns, relation.order_values)

  relation = relation.except(:select).select(values).distinct!

  id_rows = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, "SQL") }
  # CPK
  #id_rows.map { |row| row[primary_key] }
  id_rows.map do |row|
    @klass.primary_keys.map do |key|
      row[key]
    end
  end
end
ordered_relation() click to toggle source
# File lib/composite_primary_keys/relation/finder_methods.rb, line 224
def ordered_relation
  if order_values.empty? && (implicit_order_column || primary_key)
    # CPK
    # order(table[implicit_order_column || primary_key].asc)
    order(Array(implicit_order_column || primary_key).map {|key| table[key].asc})
  else
    self
  end
end