Class: SlimScrooge::Callsite
- Inherits:
-
Object
- Object
- SlimScrooge::Callsite
- 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
-
#columns_hash ⇒ Object
readonly
Returns the value of attribute columns_hash.
-
#model_class_name ⇒ Object
readonly
Returns the value of attribute model_class_name.
-
#primary_key ⇒ Object
readonly
Returns the value of attribute primary_key.
-
#seen_columns ⇒ Object
Returns the value of attribute seen_columns.
Class Method Summary collapse
-
.make_callsite(model_class, original_sql) ⇒ Object
Make a callsite if the query is of the right type for us to optimise.
-
.select_regexp(table_name) ⇒ Object
The regexp that enables us to replace the * from SELECT * with the list of columns we actually need.
-
.use_scrooge?(model_class, original_sql) ⇒ Boolean
Check if query can be optimised.
Instance Method Summary collapse
- #connection ⇒ Object
-
#essential_columns(model_class) ⇒ Object
List of columns that should always be fetched no matter what.
-
#initialize(model_class) ⇒ Callsite
constructor
A new instance of Callsite.
-
#missing_columns(fetched_columns) ⇒ Object
List if columns what were not fetched.
-
#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.
-
#scrooge_select_sql(set) ⇒ Object
Change a set of columns into a correctly quoted comma separated list.
-
#scrooged_sql(seen_columns, sql) ⇒ Object
Returns suitable sql given a list of columns and the original query.
Constructor Details
#initialize(model_class) ⇒ Callsite
Returns a new instance of Callsite.
43 44 45 46 47 48 49 50 51 52 |
# File 'lib/slim_scrooge/callsite.rb', line 43 def initialize(model_class) @all_columns = SimpleSet.new(model_class.column_names) @model_class_name = model_class.to_s @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(model_class)) end |
Instance Attribute Details
#columns_hash ⇒ Object (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_class_name ⇒ Object (readonly)
Returns the value of attribute model_class_name.
12 13 14 |
# File 'lib/slim_scrooge/callsite.rb', line 12 def model_class_name @model_class_name end |
#primary_key ⇒ Object (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_columns ⇒ Object
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
38 39 40 |
# File 'lib/slim_scrooge/callsite.rb', line 38 def select_regexp(table_name) %r{SELECT +(?:[`"]?#{table_name}[`"]?.)?\* +FROM} end |
.use_scrooge?(model_class, original_sql) ⇒ Boolean
Check if query can be optimised
27 28 29 30 31 32 33 |
# File 'lib/slim_scrooge/callsite.rb', line 27 def use_scrooge?(model_class, original_sql) original_sql = original_sql.to_sql if original_sql.respond_to?(:to_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
#connection ⇒ Object
98 99 100 |
# File 'lib/slim_scrooge/callsite.rb', line 98 def connection @model_class_name.constantize.connection end |
#essential_columns(model_class) ⇒ Object
List of columns that should always be fetched no matter what
56 57 58 59 60 61 62 63 |
# File 'lib/slim_scrooge/callsite.rb', line 56 def essential_columns(model_class) model_class.reflect_on_all_associations.inject([@primary_key]) do |arr, assoc| if assoc.[:dependent] && assoc.macro == :belongs_to arr << assoc.respond_to?(:foreign_key) ? assoc.foreign_key : assoc.primary_key_name end arr end end |
#missing_columns(fetched_columns) ⇒ Object
List if columns what were not fetched
85 86 87 |
# File 'lib/slim_scrooge/callsite.rb', line 85 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
92 93 94 95 96 |
# File 'lib/slim_scrooge/callsite.rb', line 92 def reload_sql(primary_keys, fetched_columns) sql_keys = primary_keys.collect{|pk| "#{connection.quote_column_name(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
104 105 106 107 108 |
# File 'lib/slim_scrooge/callsite.rb', line 104 def scrooge_select_sql(set) set.collect do |name| "#{@quoted_table_name}.#{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
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/slim_scrooge/callsite.rb', line 67 def scrooged_sql(seen_columns, sql) if sql.respond_to?(:project) # modify the query - this is a hack that needs to be fixed projections = sql.instance_variable_get(:@ctx).projections select_cols = seen_columns.collect do |name| arel_attr = projections[0].dup arel_attr.name = name arel_attr end projections.replace(select_cols) sql else sql.gsub(@select_regexp, "SELECT #{scrooge_select_sql(seen_columns)} FROM") end end |