Class: SlimScrooge::Callsite

Inherits:
Object
  • Object
show all
Defined in:
lib/slim_scrooge/callsite.rb

Overview

A Callsite contains the list of columns that are accessed when an SQL query is made from a particular place in the app

Constant Summary collapse

ScroogeComma =
",".freeze
ScroogeRegexJoin =
/(?:LEFT|INNER|OUTER|CROSS)*\s*(?:STRAIGHT_JOIN|JOIN)/i

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(model_class) ⇒ Callsite

Returns a new instance of Callsite.



41
42
43
44
45
46
47
48
49
50
# File 'lib/slim_scrooge/callsite.rb', line 41

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
  @quoted_primary_key = model_class.connection.quote_column_name(@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

Instance Attribute Details

#columns_hashObject (readonly)

Returns the value of attribute columns_hash.



12
13
14
# File 'lib/slim_scrooge/callsite.rb', line 12

def columns_hash
  @columns_hash
end

#model_classObject (readonly)

Returns the value of attribute model_class.



12
13
14
# File 'lib/slim_scrooge/callsite.rb', line 12

def model_class
  @model_class
end

#primary_keyObject (readonly)

Returns the value of attribute primary_key.



12
13
14
# File 'lib/slim_scrooge/callsite.rb', line 12

def primary_key
  @primary_key
end

#seen_columnsObject

Returns the value of attribute seen_columns.



11
12
13
# File 'lib/slim_scrooge/callsite.rb', line 11

def seen_columns
  @seen_columns
end

Class Method Details

.make_callsite(model_class, original_sql) ⇒ Object

Make a callsite if the query is of the right type for us to optimise



17
18
19
20
21
22
23
# File 'lib/slim_scrooge/callsite.rb', line 17

def make_callsite(model_class, original_sql)
  if use_scrooge?(model_class, original_sql)
    new(model_class)
  else
    nil
  end
end

.select_regexp(table_name) ⇒ Object

The regexp that enables us to replace the * from SELECT * with the list of columns we actually need



36
37
38
# File 'lib/slim_scrooge/callsite.rb', line 36

def select_regexp(table_name)
  %r{SELECT (`?(?:#{table_name})?`?.?\\*) FROM}
end

.use_scrooge?(model_class, original_sql) ⇒ Boolean

Check if query can be optimised

Returns:

  • (Boolean)


27
28
29
30
31
# File 'lib/slim_scrooge/callsite.rb', line 27

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

Instance Method Details

#essential_columnsObject

List of columns that should always be fetched no matter what



54
55
56
57
58
59
60
61
# File 'lib/slim_scrooge/callsite.rb', line 54

def essential_columns
  @model_class.reflect_on_all_associations.inject([@primary_key]) do |arr, assoc|
    if assoc.options[:dependent] && assoc.macro == :belongs_to
      arr << assoc.association_foreign_key
    end
    arr
  end
end

#missing_columns(fetched_columns) ⇒ Object

List if columns what were not fetched



71
72
73
# File 'lib/slim_scrooge/callsite.rb', line 71

def missing_columns(fetched_columns)
  (@all_columns - SimpleSet.new(fetched_columns)) << @primary_key
end

#reload_sql(primary_keys, fetched_columns) ⇒ Object

Returns sql for fetching the unfetched columns for all the rows in the result set, specified by primary_keys



78
79
80
81
82
# File 'lib/slim_scrooge/callsite.rb', line 78

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_primary_key} IN (#{sql_keys})"
end

#scrooge_select_sql(set) ⇒ Object

Change a set of columns into a correctly quoted comma separated list



86
87
88
89
90
# File 'lib/slim_scrooge/callsite.rb', line 86

def scrooge_select_sql(set)
  set.collect do |name|
    "#{@quoted_table_name}.#{@model_class.connection.quote_column_name(name)}"
  end.join(ScroogeComma)
end

#scrooged_sql(seen_columns, sql) ⇒ Object

Returns suitable sql given a list of columns and the original query



65
66
67
# File 'lib/slim_scrooge/callsite.rb', line 65

def scrooged_sql(seen_columns, sql)
  sql.gsub(@select_regexp, "SELECT #{scrooge_select_sql(seen_columns)} FROM")
end