# Author: Stephen Sykes module SlimScrooge class Callsite ScroogeComma = ",".freeze ScroogeRegexJoin = /(?:LEFT|INNER|OUTER|CROSS)*\s*(?:STRAIGHT_JOIN|JOIN)/i attr_accessor :seen_columns attr_reader :columns_hash, :primary_key, :model_class class << self def make_callsite(model_class, original_sql) if use_scrooge?(model_class, original_sql) new(model_class) else nil end end def use_scrooge?(model_class, original_sql) original_sql =~ select_regexp(model_class.table_name) && model_class.columns_hash.has_key?(model_class.primary_key) && original_sql !~ ScroogeRegexJoin end def select_regexp(table_name) %r{SELECT (`?(?:#{table_name})?`?.?\\*) FROM} end end def initialize(model_class) @all_columns = SimpleSet.new(model_class.column_names) @model_class = model_class @quoted_table_name = model_class.quoted_table_name @primary_key = model_class.primary_key @columns_hash = model_class.columns_hash @select_regexp = self.class.select_regexp(model_class.table_name) @seen_columns = SimpleSet.new(essential_columns) end def essential_columns @model_class.reflect_on_all_associations.inject([@model_class.primary_key]) do |arr, assoc| if assoc.options[:dependent] && assoc.macro == :belongs_to arr << assoc.association_foreign_key end arr end end def scrooged_sql(seen_columns, sql) sql.gsub(@select_regexp, "SELECT #{scrooge_select_sql(seen_columns)} FROM") end def missing_columns(fetched_columns) (@all_columns - SimpleSet.new(fetched_columns)) << @primary_key end def reload_sql(primary_keys, fetched_columns) sql_keys = primary_keys.collect{|pk| "'#{pk}'"}.join(ScroogeComma) cols = scrooge_select_sql(missing_columns(fetched_columns)) "SELECT #{cols} FROM #{@quoted_table_name} WHERE #{@quoted_table_name}.#{@primary_key} IN (#{sql_keys})" end def scrooge_select_sql(set) set.collect do |name| "#{@quoted_table_name}.#{@model_class.connection.quote_column_name(name)}" end.join(ScroogeComma) end end end