From 683d1ecea173fd4074155eb2e0b28035a06d7bb8 Mon Sep 17 00:00:00 2001 From: "Gun.io Whitespace Robot" Date: Tue, 31 Jan 2012 03:35:35 -0500 Subject: [PATCH] Remove whitespace [WhitespaceBot] --- README.textile | 42 ++++----- Rakefile | 2 +- VERSION.yml | 2 +- lib/callsite.rb | 54 +++++------ .../associations/association_set.rb | 30 +++---- lib/optimizations/associations/macro.rb | 42 ++++----- lib/optimizations/columns/attributes_proxy.rb | 22 ++--- lib/optimizations/columns/macro.rb | 90 +++++++++---------- .../result_sets/updateable_result_set.rb | 22 ++--- lib/scrooge.rb | 14 +-- lib/simple_set.rb | 16 ++-- test/callsite_test.rb | 12 +-- test/helper.rb | 26 +++--- test/models/mysql_column_privilege.rb | 6 +- test/models/mysql_host.rb | 6 +- test/models/mysql_table_privilege.rb | 8 +- test/models/mysql_user.rb | 8 +- test/optimizations/associations/macro_test.rb | 10 +-- test/scrooge_test.rb | 36 ++++---- 19 files changed, 224 insertions(+), 224 deletions(-) diff --git a/README.textile b/README.textile index aaecf09..05f76c8 100644 --- a/README.textile +++ b/README.textile @@ -21,7 +21,7 @@ h2. What it does Processing HotelsController#show (for 127.0.0.1 at 2009-03-18 19:29:38) [GET] Parameters: {"action"=>"show", "id"=>"8699-radisson-hotel-waterfront-cape-town", "controller"=>"hotels"} - Hotel Load Scrooged (0.3ms) SELECT `hotels`.id FROM `hotels` WHERE (`hotels`.`id` = 8699) + Hotel Load Scrooged (0.3ms) SELECT `hotels`.id FROM `hotels` WHERE (`hotels`.`id` = 8699) Rendering template within layouts/application Rendering hotels/show SQL (0.2ms) SELECT `hotels`.location_id,`hotels`.hotel_name,`hotels`.location,`hotels`.from_price,`hotels`.star_rating,`hotels`.apt,`hotels`.latitude,`hotels`.longitude,`hotels`.distance,`hotels`.narrative,`hotels`.telephone,`hotels`.important_notes,`hotels`.nearest_tube,`hotels`.nearest_rail,`hotels`.created_at,`hotels`.updated_at,`hotels`.id FROM `hotels` WHERE `hotels`.id IN ('8699') @@ -29,7 +29,7 @@ h2. What it does SQL (0.2ms) SELECT `images`.hotel_id,`images`.title,`images`.url,`images`.width,`images`.height,`images`.thumbnail_url,`images`.thumbnail_width,`images`.thumbnail_height,`images`.has_thumbnail,`images`.created_at,`images`.updated_at,`images`.id FROM `images` WHERE `images`.id IN ('488') Rendered shared/_header (0.0ms) Rendered shared/_navigation (0.2ms) - Image Load Scrooged (0.2ms) SELECT `images`.id FROM `images` WHERE (`images`.hotel_id = 8699) + Image Load Scrooged (0.2ms) SELECT `images`.id FROM `images` WHERE (`images`.hotel_id = 8699) SQL (0.2ms) SELECT `images`.hotel_id,`images`.title,`images`.url,`images`.width,`images`.height,`images`.thumbnail_url,`images`.thumbnail_width,`images`.thumbnail_height,`images`.has_thumbnail,`images`.created_at,`images`.updated_at,`images`.id FROM `images` WHERE `images`.id IN ('488') Address Columns (306.2ms) SHOW FIELDS FROM `addresses` Address Load Scrooged (3.6ms) SELECT `addresses`.id FROM `addresses` WHERE (`addresses`.hotel_id = 8699) LIMIT 1 @@ -40,20 +40,20 @@ h2. What it does Processing HotelsController#show (for 127.0.0.1 at 2009-03-18 19:29:40) [GET] Parameters: {"action"=>"show", "id"=>"8699-radisson-hotel-waterfront-cape-town", "controller"=>"hotels"} - Hotel Load Scrooged (0.3ms) SELECT `hotels`.narrative,`hotels`.from_price,`hotels`.star_rating,`hotels`.hotel_name,`hotels`.id FROM `hotels` WHERE (`hotels`.`id` = 8699) - Address Load Scrooged (0.2ms) SELECT `addresses`.id FROM `addresses` WHERE (`addresses`.hotel_id = 8699) + Hotel Load Scrooged (0.3ms) SELECT `hotels`.narrative,`hotels`.from_price,`hotels`.star_rating,`hotels`.hotel_name,`hotels`.id FROM `hotels` WHERE (`hotels`.`id` = 8699) + Address Load Scrooged (0.2ms) SELECT `addresses`.id FROM `addresses` WHERE (`addresses`.hotel_id = 8699) Rendering template within layouts/application Rendering hotels/show Image Load Scrooged (0.3ms) SELECT `images`.url,`images`.id,`images`.height,`images`.width FROM `images` WHERE (`images`.hotel_id = 8699) LIMIT 1 Rendered shared/_header (0.1ms) Rendered shared/_navigation (0.2ms) - Image Load Scrooged (0.3ms) SELECT `images`.thumbnail_width,`images`.id,`images`.thumbnail_height,`images`.thumbnail_url FROM `images` WHERE (`images`.hotel_id = 8699) + Image Load Scrooged (0.3ms) SELECT `images`.thumbnail_width,`images`.id,`images`.thumbnail_height,`images`.thumbnail_url FROM `images` WHERE (`images`.hotel_id = 8699) Rendered hotels/_show_sidebar (1.0ms) Rendered shared/_footer (0.1ms) Completed in 8ms (View: 5, DB: 1) | 200 OK [http://localhost/hotels/8699-radisson-hotel-waterfront-cape-town] - + - + h2. Suggested Use @@ -75,7 +75,7 @@ h4. As a Gem h2. Stability -The whole Rails 2.3.2 ActiveRecord test suite passes with scrooge, except for 13 failures related to callsite augmentation (note the SQL reload snippets below). Thoughts on handling or circumventing this much appreciated. +The whole Rails 2.3.2 ActiveRecord test suite passes with scrooge, except for 13 failures related to callsite augmentation (note the SQL reload snippets below). Thoughts on handling or circumventing this much appreciated.
 
@@ -87,10 +87,10 @@ test_finding_with_includes_on_belongs_to_association_with_same_include_includes_
      /opt/local/lib/ruby/gems/1.8/gems/activesupport-2.3.1/lib/active_support/testing/setup_and_teardown.rb:57:in `run']:
 5 instead of 3 queries were executed.
 Queries:
-SELECT `posts`.id,`posts`.type FROM `posts` WHERE (`posts`.`id` = 1) 
-SELECT `posts`.author_id,`posts`.title,`posts`.body,`posts`.comments_count,`posts`.taggings_count FROM `posts` WHERE (`posts`.`id` = 1) 
-SELECT `authors`.name,`authors`.id FROM `authors` WHERE (`authors`.`id` = 1) 
-SELECT `authors`.author_address_id,`authors`.author_address_extra_id FROM `authors` WHERE (`authors`.`id` = 1) 
+SELECT `posts`.id,`posts`.type FROM `posts` WHERE (`posts`.`id` = 1)
+SELECT `posts`.author_id,`posts`.title,`posts`.body,`posts`.comments_count,`posts`.taggings_count FROM `posts` WHERE (`posts`.`id` = 1)
+SELECT `authors`.name,`authors`.id FROM `authors` WHERE (`authors`.`id` = 1)
+SELECT `authors`.author_address_id,`authors`.author_address_extra_id FROM `authors` WHERE (`authors`.`id` = 1)
 SELECT `author_addresses`.id FROM `author_addresses` WHERE (`author_addresses`.`id` = 1) .
 <3> expected but was
 <5>.
@@ -149,25 +149,25 @@ Ruby allows introspection of the call tree through
 
 
   Kernel#caller
-	
-
+
+
-Scrooge analyzes the last 10 calltree elements that triggered +Scrooge analyzes the last 10 calltree elements that triggered
 
   ActiveRecord::Base.find_by_sql
-	
+
 
Lets refer to that as a callsite, or signature. -Thus given SQL such as +Thus given SQL such as
 
 "SELECT * FROM `images` WHERE (`images`.hotel_id = 11697)  LIMIT 1"
-	
+
 
Called from our application helper @@ -175,17 +175,17 @@ Called from our application helper
 
 ["/Users/lourens/projects/superbreak_app/vendor/plugins/scrooge/rails/../lib/scrooge.rb:27:in `find_by_sql'", "/Users/lourens/projects/superbreak_app/vendor/rails/activerecord/lib/active_record/base.rb:1557:in `find_every'", "/Users/lourens/projects/superbreak_app/vendor/rails/activerecord/lib/active_record/base.rb:1514:in `find_initial'", "/Users/lourens/projects/superbreak_app/vendor/rails/activerecord/lib/active_record/base.rb:613:in `find'", "/Users/lourens/projects/superbreak_app/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb:60:in `find'", "/Users/lourens/projects/superbreak_app/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb:67:in `first'", "/Users/lourens/projects/superbreak_app/app/helpers/application_helper.rb:60:in `hotel_image'", "/Users/lourens/projects/superbreak_app/app/views/hotels/_hotel.html.erb:4:in `_run_erb_app47views47hotels47_hotel46html46erb_locals_hotel_hotel_counter_object'", "/Users/lourens/projects/superbreak_app/vendor/rails/actionpack/lib/action_view/renderable.rb:36:in `send'", "/Users/lourens/projects/superbreak_app/vendor/rails/actionpack/lib/action_view/renderable.rb:36:in `render'", "/Users/lourens/projects/superbreak_app/vendor/rails/actionpack/lib/action_view/renderable_partial.rb:20:in `render'"]
-	
+
 
We can generate a unique callsite identifier with the following calculation :
 
 (The above calltree <<  "SELECT * FROM `images` ).hash " # cut off conditions etc.
-	
+
 
-Callsites are tracked on a per model ( table name ) basis. +Callsites are tracked on a per model ( table name ) basis. h4. Scope diff --git a/Rakefile b/Rakefile index 0b9c79a..8df7270 100644 --- a/Rakefile +++ b/Rakefile @@ -9,7 +9,7 @@ task :default => [:test_with_active_record, :test_scrooge] task :test => :default Rake::TestTask.new( :test_with_active_record ) { |t| - t.libs << AR_TEST_SUITE << Scrooge::Test.connection() + t.libs << AR_TEST_SUITE << Scrooge::Test.connection() t.test_files = Scrooge::Test.active_record_test_files() t.ruby_opts = ["-r #{File.join( File.dirname(__FILE__), 'test', 'setup' )}"] t.verbose = true diff --git a/VERSION.yml b/VERSION.yml index f4406dc..750b78c 100644 --- a/VERSION.yml +++ b/VERSION.yml @@ -1,4 +1,4 @@ ---- +--- :major: 3 :minor: 0 :patch: 0 diff --git a/lib/callsite.rb b/lib/callsite.rb index bcbfa14..891ffae 100644 --- a/lib/callsite.rb +++ b/lib/callsite.rb @@ -1,28 +1,28 @@ module Scrooge class Callsite - - # Represents a Callsite and is a container for any columns and + + # Represents a Callsite and is a container for any columns and # associations referenced at the callsite. # - + Mtx = Mutex.new # mutex should perhaps be per-instance at the expense of a little memory attr_accessor :klass, :signature, :columns, :associations - + def initialize( klass, signature ) @klass = klass @signature = signature end - + # Flag a column as seen # def column!( column ) columns && Mtx.synchronize { @columns << column } end - + # Flag an association as seen # association should be an AssociationReflection object # @@ -31,33 +31,33 @@ def association!(association, record_id) associations.register(association, record_id) end end - + def inspect "<##{@klass.name} :select => '#{@klass.scrooge_select_sql( columns )}', :include => [#{associations_for_inspect}]>" end - + # Lazy init default columns # def default_columns @default_columns || Mtx.synchronize { @default_columns = setup_columns } end - + # Lazy init columns # def columns - @columns || default_columns && Mtx.synchronize { @columns = @default_columns.dup } + @columns || default_columns && Mtx.synchronize { @columns = @default_columns.dup } end - + # Lazy init associations # def associations @associations || Mtx.synchronize { @associations = setup_associations } end - + def has_associations? @associations end - + # Analyze previously collected information # and reset ready for a new query # @@ -66,15 +66,15 @@ def reset associations.reset end end - + def register_result_set(result_set) if has_associations? associations.register_result_set(result_set) end end - + private - + def associations_for_inspect if has_associations? associations.to_preload.map{|a| ":#{a.to_s}" }.join(', ') @@ -82,36 +82,36 @@ def associations_for_inspect "" end end - + # Only register associations that isn't polymorphic or a collection # def preloadable_association?( association ) @klass.preloadable_associations.include?( association.to_sym ) end - + # Is the table a container for STI models ? - # + # def inheritable? @klass.columns_hash.has_key?( inheritance_column ) end - + # Ensure that at least the primary key and optionally the inheritance - # column ( for STI ) is set. + # column ( for STI ) is set. # def setup_columns if inheritable? SimpleSet.new([primary_key, inheritance_column]) else primary_key.blank? ? SimpleSet.new : SimpleSet.new([primary_key]) - end + end end - + # Start with no registered associations # def setup_associations Optimizations::Associations::AssociationSet.new end - + # Memoize a string representation of the inheritance column # def inheritance_column @@ -119,10 +119,10 @@ def inheritance_column end # Memoize a string representation of the primary - # + # def primary_key @primary_key ||= @klass.primary_key.to_s - end - + end + end end \ No newline at end of file diff --git a/lib/optimizations/associations/association_set.rb b/lib/optimizations/associations/association_set.rb index 736cb97..b38e9a5 100644 --- a/lib/optimizations/associations/association_set.rb +++ b/lib/optimizations/associations/association_set.rb @@ -1,9 +1,9 @@ module Scrooge - module Optimizations + module Optimizations module Associations # Keeps track of how a result set is used to access associations - # Each callsite where associations are accessed will contain one of + # Each callsite where associations are accessed will contain one of # these objects. # Each thread will collect data, and we check this data before each # fetch from the database, adding any associations that are needed @@ -21,58 +21,58 @@ def initialize @associations = SimpleSet.new @as_data_id = :"association_data_#{object_id}" end - + def register(association, record_id) assoc_data.register(association, record_id) end - + def register_result_set(result_set) assoc_data.register_result_set(result_set) end - + def reset Mtx.synchronize do @associations |= assoc_data.to_preload end assoc_data.reset end - + def to_preload @associations.to_a end - + private - + def assoc_data Thread.current[@as_data_id] ||= AssociationData.new end end - + class AssociationData def initialize reset end - + def reset @associations = {} @result_set_size = 0 end - + def register(association, record_id) if @result_set_size > 1 assoc = (@associations[association.name] ||= AssociationIdentity.new(association)) assoc.register(record_id) end end - + def register_result_set(result_set) @result_set_size = result_set.size end - + def to_preload @associations.values.select { |association| preload_this_assoc?(association) }.map(&:name) end - + private # Calculate the benefit of preloading an association @@ -81,7 +81,7 @@ def to_preload # to access the association - more than 25% and we preload # # TODO: more rules and analysis for different association types - # + # def preload_this_assoc?(association) if @result_set_size <= 1 false diff --git a/lib/optimizations/associations/macro.rb b/lib/optimizations/associations/macro.rb index e6ee454..d2b7815 100644 --- a/lib/optimizations/associations/macro.rb +++ b/lib/optimizations/associations/macro.rb @@ -1,33 +1,33 @@ module Scrooge - module Optimizations + module Optimizations module Associations module Macro - + class << self - + # Inject into ActiveRecord # def install! unless scrooge_installed? ActiveRecord::Base.send( :extend, SingletonMethods ) - ActiveRecord::Associations::AssociationProxy.send( :include, InstanceMethods ) + ActiveRecord::Associations::AssociationProxy.send( :include, InstanceMethods ) end end - + protected - + def scrooge_installed? ActiveRecord::Associations::AssociationProxy.included_modules.include?( InstanceMethods ) end - + end - + end - + module SingletonMethods - + @@preloadable_associations = {} - + def self.extended( base ) eigen = class << base; self; end # not used at present @@ -53,18 +53,18 @@ def scrooge_preloading_exclude Thread.current[:scrooge_preloading] = false end end - + # Let's not preload polymorphic associations or collections - # + # def preloadable_associations - @@preloadable_associations[self.name] ||= + @@preloadable_associations[self.name] ||= reflect_on_all_associations.reject{|a| a.options[:polymorphic] || a.macro == :has_many}.map(&:name) end end - + module InstanceMethods - + def self.included( base ) base.alias_method_chain :load_target, :scrooge end @@ -78,7 +78,7 @@ def load_target_with_scrooge end private - + # Register an association with Scrooge # def scrooge_seen_association!( association ) @@ -86,13 +86,13 @@ def scrooge_seen_association!( association ) @owner.class.scrooge_callsite(callsite_signature).association!(association, @owner.id) end end - + def callsite_signature @owner.instance_variable_get(:@attributes).callsite_signature end - + end - + end end -end \ No newline at end of file +end \ No newline at end of file diff --git a/lib/optimizations/columns/attributes_proxy.rb b/lib/optimizations/columns/attributes_proxy.rb index 29b94ff..e1cf336 100644 --- a/lib/optimizations/columns/attributes_proxy.rb +++ b/lib/optimizations/columns/attributes_proxy.rb @@ -4,7 +4,7 @@ module Columns class UnscroogedAttributes < Hash # Hash container for attributes when scrooge is not used - # + # def self.setup(record) new.replace(record) @@ -18,7 +18,7 @@ def update(hash) end alias_method :merge!, :update - + # Don't try to reload one of these # def fully_fetched @@ -27,9 +27,9 @@ def fully_fetched end class ScroogedAttributes < Hash - + # Hash container for attributes with scrooge monitoring of attribute access - # + # attr_accessor :fully_fetched, :klass, :updateable_result_set @@ -62,7 +62,7 @@ def []=(attr_name, value) add_to_scrooge_columns(attr_name) super end - + alias_method :store, :[]= def dup @@ -88,7 +88,7 @@ def update(hash) @fully_fetched = true super(hash.to_hash) end - + alias_method :merge!, :update def fetch_remaining @@ -100,22 +100,22 @@ def fetch_remaining @fully_fetched = true end end - + def callsite_signature @updateable_result_set.callsite_signature end - + def scrooge_columns @scrooge_columns || @updateable_result_set.scrooge_columns end - + protected def fetch_remaining!( columns_to_fetch ) @updateable_result_set.updaters_attributes = self # for after_initialize & after_find @updateable_result_set.reload_columns!(columns_to_fetch) end - + def augment_callsite!( attr_name ) @klass.scrooge_seen_column!(callsite_signature, attr_name) end @@ -138,4 +138,4 @@ def dup_self end end end -end +end diff --git a/lib/optimizations/columns/macro.rb b/lib/optimizations/columns/macro.rb index 381da06..f4be354 100644 --- a/lib/optimizations/columns/macro.rb +++ b/lib/optimizations/columns/macro.rb @@ -1,74 +1,74 @@ module Scrooge - module Optimizations + module Optimizations module Columns module Macro - + class << self - + # Inject into ActiveRecord # def install! if scrooge_installable? ActiveRecord::Base.send( :extend, SingletonMethods ) - ActiveRecord::Base.send( :include, InstanceMethods ) - end + ActiveRecord::Base.send( :include, InstanceMethods ) + end end - + private - + def scrooge_installable? !ActiveRecord::Base.included_modules.include?( InstanceMethods ) end - + end - + end - + module SingletonMethods - + ScroogeBlankString = "".freeze - ScroogeComma = ",".freeze + ScroogeComma = ",".freeze ScroogeRegexSanitize = /(?:LIMIT|WHERE|FROM|GROUP\s*BY|HAVING|ORDER\s*BY|PROCEDURE|FOR\s*UPDATE|INTO\s*OUTFILE).*/i ScroogeRegexJoin = /(?:left|inner|outer|cross)*\s*(?:straight_join|join)/i - + @@scrooge_select_regexes = {} - + # Augment a given callsite signature with a column / attribute. # def scrooge_seen_column!( callsite_signature, attr_name ) scrooge_callsite( callsite_signature ).column!( attr_name ) - end - + end + # Generates a SELECT snippet for this Model from a given Set of columns # def scrooge_select_sql( set ) set.map{|a| attribute_with_table( a ) }.join( ScroogeComma ) - end - + end + # Marshal.load - # + # def _load(str) Marshal.load(str) end - - # Efficient reloading - get the hash with missing attributes directly from the + + # Efficient reloading - get the hash with missing attributes directly from the # underlying connection. # def scrooge_reload( p_keys, missing_columns ) sql_keys = p_keys.collect{|pk| "'#{pk}'"}.join(ScroogeComma) connection.send( :select, "SELECT #{scrooge_select_sql(missing_columns)} FROM #{quoted_table_name} WHERE #{quoted_table_name}.#{primary_key} IN (#{sql_keys})", "#{name} Scrooge Reload" ) end - + # Only scope n-1 rows by default. - # + # def scope_with_scrooge?( sql ) - sql =~ scrooge_select_regex && + sql =~ scrooge_select_regex && columns_hash.has_key?(self.primary_key.to_s) && sql !~ ScroogeRegexJoin end - + private - + # Find through callsites. # def find_by_sql_with_scrooge(sql) @@ -95,7 +95,7 @@ def find_by_sql_with_scrooge(sql) result_set end - + def find_by_sql_without_scrooge(sql) connection.select_all(sanitize_sql(sql), "#{name} Load").collect! do |record| instantiate( UnscroogedAttributes.setup(record) ) @@ -104,7 +104,7 @@ def find_by_sql_without_scrooge(sql) # Generate a regex that respects the table name as well to catch # verbose SQL from JOINS etc. - # + # def scrooge_select_regex @@scrooge_select_regexes[self.table_name] ||= Regexp.compile( "SELECT (`?(?:#{table_name})?`?.?\\*) FROM" ) end @@ -114,11 +114,11 @@ def scrooge_select_regex def callsite_sql( sql ) sql.gsub(ScroogeRegexSanitize, ScroogeBlankString) end - + end - + module InstanceMethods - + def self.included( base ) base.alias_method_chain :delete, :scrooge base.alias_method_chain :destroy, :scrooge @@ -126,27 +126,27 @@ def self.included( base ) base.alias_method_chain :attributes_from_column_definition, :scrooge base.alias_method_chain :becomes, :scrooge end - + # Is this instance being handled by scrooge? # def scrooged? @attributes.is_a?(ScroogedAttributes) - end - + end + # Delete should fully load all the attributes before the @attributes hash is frozen # def delete_with_scrooge scrooge_fetch_remaining delete_without_scrooge - end - + end + # Destroy should fully load all the attributes before the @attributes hash is frozen # def destroy_with_scrooge scrooge_fetch_remaining destroy_without_scrooge - end - + end + # Augment callsite info for new model class when using STI # def becomes_with_scrooge(klass) @@ -156,7 +156,7 @@ def becomes_with_scrooge(klass) end end becomes_without_scrooge(klass) - end + end # Marshal # force a full load if needed, and remove any possibility for missing attr flagging @@ -169,7 +169,7 @@ def _dump(depth) scrooge_dump_unflag_this str end - + # Enables us to use Marshal.dump inside our _dump method without an infinite loop # def respond_to_with_scrooge?(symbol, include_private=false) @@ -179,7 +179,7 @@ def respond_to_with_scrooge?(symbol, include_private=false) respond_to_without_scrooge?(symbol, include_private) end end - + # Expose this record's callsite signature # def callsite_signature @@ -213,7 +213,7 @@ def scrooge_dump_flagged? def scrooge_fetch_remaining @attributes.fetch_remaining if scrooged? end - + # Dumped objects should not contain object_ids of old result sets # def scrooge_invalidate_updateable_result_set @@ -221,15 +221,15 @@ def scrooge_invalidate_updateable_result_set @attributes.updateable_result_set = ResultSets::UpdateableResultSet.new(nil, self, callsite_signature, @attributes.scrooge_columns) end end - + # New objects should get an UnscroogedAttributes as their @attributes hash # def attributes_from_column_definition_with_scrooge UnscroogedAttributes.setup(attributes_from_column_definition_without_scrooge) end - + end - + end end end diff --git a/lib/optimizations/result_sets/updateable_result_set.rb b/lib/optimizations/result_sets/updateable_result_set.rb index dbf670b..c586b8f 100644 --- a/lib/optimizations/result_sets/updateable_result_set.rb +++ b/lib/optimizations/result_sets/updateable_result_set.rb @@ -2,13 +2,13 @@ module Scrooge module Optimizations module ResultSets class UpdateableResultSet - + # Contains a weak referernce to the result set, and can update from DB # - + attr_accessor :updaters_attributes attr_reader :callsite_signature, :scrooge_columns - + def initialize(result_set_array, klass, callsite_signature, scrooge_columns) if result_set_array @result_set_object_id = result_set_array.object_id @@ -18,7 +18,7 @@ def initialize(result_set_array, klass, callsite_signature, scrooge_columns) @callsite_signature = callsite_signature @scrooge_columns = scrooge_columns end - + # Called by a ScroogedAttributes hash when it is asked for a column # that was not fetched from the DB # @@ -45,7 +45,7 @@ def result_set_attributes memo end.uniq end - + # The result set is weak referenced by its object_id # So we check that a unique id matches what we have remembered to make sure # that we got the right object (object ids are recycled by ruby) @@ -57,7 +57,7 @@ def result_set rescue RangeError nil end - + # When called from after_find and after_initialize, the object # being accessed (and causing the reload) is not in the result set yet. # We make sure that we add its attributes to result_set_attributes so it @@ -66,7 +66,7 @@ def result_set def default_attributes [@updaters_attributes] end - + # Ids of the items to be reloaded # def result_set_ids @@ -77,7 +77,7 @@ def result_set_ids memo end end - + # Update the result set with attributes provided, as returned by # the sql server # @@ -90,18 +90,18 @@ def update_with(remaining_attributes) end end end - + # Make an efficient data structure to access items when the # primary key is known # def hash_by_primary_key(rows) rows.inject({}) {|memo, row| memo[row[primary_key_name]] = row; memo} end - + def primary_key_name @klass.primary_key end - + end end end diff --git a/lib/scrooge.rb b/lib/scrooge.rb index 9876e65..010fdb1 100644 --- a/lib/scrooge.rb +++ b/lib/scrooge.rb @@ -25,7 +25,7 @@ class << self # Determine if a given SQL string is a candidate for callsite <=> columns # optimization. - # + # def find_by_sql(sql) if scope_with_scrooge?(sql) find_by_sql_with_scrooge(sql) @@ -33,9 +33,9 @@ def find_by_sql(sql) find_by_sql_without_scrooge(sql) end end - + # Expose known callsites for this model - # + # def scrooge_callsites @@scrooge_callsites[table_name] || ScroogeMutex.synchronize { @@scrooge_callsites[table_name] = {} } end @@ -49,7 +49,7 @@ def scrooge_callsite( callsite_signature ) end # Flush all known callsites. Mostly a test helper. - # + # def scrooge_flush_callsites! ScroogeMutex.synchronize do @@scrooge_callsites[table_name] = {} @@ -64,12 +64,12 @@ def scrooge_unlink_callsite!( callsite_signature ) ScroogeMutex.synchronize do @@scrooge_callsites.delete(callsite_signature) end - end + end # Initialize a callsite # def callsite( signature ) - Scrooge::Callsite.new( self, signature ) + Scrooge::Callsite.new( self, signature ) end # Link the column to its table @@ -77,7 +77,7 @@ def callsite( signature ) def attribute_with_table( attr_name ) "#{quoted_table_name}.#{connection.quote_column_name(attr_name.to_s)}" end - + # Computes a unique signature from a given call stack and supplementary # context information. # diff --git a/lib/simple_set.rb b/lib/simple_set.rb index 17d5853..56fbd53 100644 --- a/lib/simple_set.rb +++ b/lib/simple_set.rb @@ -1,7 +1,7 @@ module Scrooge class SimpleSet < Hash - + class << self ## # Creates a new set containing the given objects @@ -13,7 +13,7 @@ def [](*ary) new(ary) end end - + ## # Create a new SimpleSet containing the unique members of _arr_ # @@ -25,7 +25,7 @@ def [](*ary) def initialize(arr = []) Array(arr).each {|x| self[x] = true} end - + ## # Add a value to the set, and return it # @@ -38,7 +38,7 @@ def <<(value) self[value] = true self end - + ## # Merge _arr_ with receiver, producing the union of receiver & _arr_ # @@ -54,7 +54,7 @@ def merge(arr) super(arr.inject({}) {|s,x| s[x] = true; s }) end alias_method :|, :merge - + ## # Invokes block once for each item in the set. Creates an array # containing the values returned by the block. @@ -69,7 +69,7 @@ def collect(&block) keys.collect(&block) end alias_method :map, :collect - + ## # Get a human readable version of the set. # @@ -82,10 +82,10 @@ def collect(&block) def inspect "#" end - + # def to_a alias_method :to_a, :keys - + end # SimpleSet end \ No newline at end of file diff --git a/test/callsite_test.rb b/test/callsite_test.rb index eadb432..7b12888 100644 --- a/test/callsite_test.rb +++ b/test/callsite_test.rb @@ -1,13 +1,13 @@ require "#{File.dirname(__FILE__)}/helper" - + Scrooge::Test.prepare! class CallsiteTest < ActiveSupport::TestCase - + def setup @callsite = Scrooge::Callsite.new( MysqlTablePrivilege, 123456 ) end - + test "should initialize with a default set of columns" do assert @callsite.columns.empty? assert_equal Scrooge::Callsite.new( MysqlUser, 123456 ).columns, SimpleSet["User"] @@ -21,13 +21,13 @@ def setup @callsite.column! :db assert_equal @callsite.inspect, "<#MysqlTablePrivilege :select => '`tables_priv`.db', :include => [:mysql_user]>" end - + test "should flag a column as seen" do assert_difference '@callsite.columns.size' do @callsite.column! :Db end end - + test "should flag only preloadable associations as seen" do assert_no_difference '@callsite.associations.to_preload.size' do @callsite.association! :undefined, 123456 @@ -38,4 +38,4 @@ def setup end end -end \ No newline at end of file +end \ No newline at end of file diff --git a/test/helper.rb b/test/helper.rb index bd61e8b..3bdf150 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -6,23 +6,23 @@ module Scrooge class Test - + MODELS_DIR = "#{File.dirname(__FILE__)}/models".freeze - + class << self - + def prepare! require 'test/unit' connect! require File.join( File.dirname(__FILE__), 'scrooge_helper' ) unless defined?(ActiveRecord::Base.connection.class::IGNORED_SQL) - require_models() + require_models() end - + def setup! setup_constants! setup_config! end - + def connection File.join( AR_TEST_SUITE, 'connections', 'native_mysql' ) end @@ -48,8 +48,8 @@ def connect! def require_models Dir.entries( MODELS_DIR ).grep(/.rb/).each do |model| require_model( model ) - end - end + end + end def require_model( model ) require "#{MODELS_DIR}/#{model}" @@ -57,11 +57,11 @@ def require_model( model ) def setup_constants! set_constant( 'MYSQL_DB_USER' ){ 'rails' } - set_constant( 'AR_TEST_SUITE' ) do + set_constant( 'AR_TEST_SUITE' ) do find_active_record_test_suite() end end - + def setup_config! unless Object.const_defined?( 'MIGRATIONS_ROOT' ) require "#{::AR_TEST_SUITE}/config" @@ -71,7 +71,7 @@ def setup_config! def set_constant( constant ) Object.const_set(constant, yield ) unless Object.const_defined?( constant ) end - + def find_active_record_test_suite ts = ($:).grep( /activerecord/ ).last.split('/') ts.pop @@ -81,8 +81,8 @@ def find_active_record_test_suite def glob( pattern ) Dir.glob( pattern ) - end - + end + end end end diff --git a/test/models/mysql_column_privilege.rb b/test/models/mysql_column_privilege.rb index 9ed11fa..80178f2 100644 --- a/test/models/mysql_column_privilege.rb +++ b/test/models/mysql_column_privilege.rb @@ -1,7 +1,7 @@ class MysqlColumnPrivilege < ActiveRecord::Base set_table_name 'columns_priv' - set_primary_key nil - + set_primary_key nil + belongs_to :mysql_user, :class_name => 'MysqlUser', :foreign_key => 'User' - + end \ No newline at end of file diff --git a/test/models/mysql_host.rb b/test/models/mysql_host.rb index 875b0b2..9e71282 100644 --- a/test/models/mysql_host.rb +++ b/test/models/mysql_host.rb @@ -1,5 +1,5 @@ -class MysqlHost < ActiveRecord::Base +class MysqlHost < ActiveRecord::Base set_table_name 'host' set_primary_key 'Host' - -end \ No newline at end of file + +end \ No newline at end of file diff --git a/test/models/mysql_table_privilege.rb b/test/models/mysql_table_privilege.rb index f3f0cbc..8574fca 100644 --- a/test/models/mysql_table_privilege.rb +++ b/test/models/mysql_table_privilege.rb @@ -1,8 +1,8 @@ class MysqlTablePrivilege < ActiveRecord::Base set_table_name 'tables_priv' - set_primary_key nil - + set_primary_key nil + belongs_to :mysql_user, :class_name => 'MysqlUser', :foreign_key => 'User' - belongs_to :column_privilege, :class_name => 'MysqlColumnPrivilege', :foreign_key => 'Column_priv' - + belongs_to :column_privilege, :class_name => 'MysqlColumnPrivilege', :foreign_key => 'Column_priv' + end \ No newline at end of file diff --git a/test/models/mysql_user.rb b/test/models/mysql_user.rb index 77ffd2f..933ba5d 100644 --- a/test/models/mysql_user.rb +++ b/test/models/mysql_user.rb @@ -1,13 +1,13 @@ -class MysqlUser < ActiveRecord::Base +class MysqlUser < ActiveRecord::Base set_table_name 'user' set_primary_key 'User' - + has_many :table_privileges, :class_name => 'MysqlTablePrivilege', :foreign_key => 'User' has_many :column_privileges, :class_name => 'MysqlColumnPrivilege', :foreign_key => 'User' belongs_to :host, :class_name => 'MysqlHost', :foreign_key => 'Host' - + def after_initialize max_connections if @attributes.has_key?("max_user_connections") end - + end \ No newline at end of file diff --git a/test/optimizations/associations/macro_test.rb b/test/optimizations/associations/macro_test.rb index f9997e0..064ecaf 100644 --- a/test/optimizations/associations/macro_test.rb +++ b/test/optimizations/associations/macro_test.rb @@ -1,9 +1,9 @@ require "#{File.dirname(__FILE__)}/../../helper" - + Scrooge::Test.prepare! class OptimizationsAssociationsMacroTest < ActiveSupport::TestCase - + test "should be able to flag any associations instantiated from a record" do @user = MysqlUser.find(:first) @user.host @@ -16,12 +16,12 @@ class OptimizationsAssociationsMacroTest < ActiveSupport::TestCase @user.host assert_equal [], MysqlUser.scrooge_callsite( @user.callsite_signature ).associations.to_preload end - + test "should be able to identify all preloadable associations for a given Model" do assert_equal MysqlUser.preloadable_associations, [:host] assert_equal MysqlHost.preloadable_associations, [] assert_equal MysqlColumnPrivilege.preloadable_associations, [:mysql_user] assert_equal MysqlTablePrivilege.preloadable_associations, [:mysql_user, :column_privilege] end - -end \ No newline at end of file + +end \ No newline at end of file diff --git a/test/scrooge_test.rb b/test/scrooge_test.rb index a207a21..af48358 100644 --- a/test/scrooge_test.rb +++ b/test/scrooge_test.rb @@ -11,30 +11,30 @@ class ScroogeTest < ActiveRecord::TestCase test "should not attempt to optimize models without a defined primary key" do MysqlUser.stubs(:primary_key).returns('undefined') MysqlUser.expects(:find_by_sql_with_scrooge).never - MysqlUser.find(:first) - end - + MysqlUser.find(:first) + end + test "should not optimize any SQL other than result retrieval" do - MysqlUser.expects(:find_by_sql_with_scrooge).never + MysqlUser.expects(:find_by_sql_with_scrooge).never MysqlUser.find_by_sql("SHOW fields from mysql.user") - end - + end + test "should not optimize inner joins" do - MysqlUser.expects(:find_by_sql_with_scrooge).never + MysqlUser.expects(:find_by_sql_with_scrooge).never MysqlUser.find_by_sql("SELECT * FROM columns_priv INNER JOIN user ON columns_priv.User = user.User") end - + test "should be able to flag applicable records as being scrooged" do assert MysqlUser.find(:first).scrooged? assert MysqlUser.find_by_sql( "SELECT * FROM mysql.user WHERE User = 'root'" ).first.scrooged? end - + test "should be able to track callsites" do assert_difference 'MysqlUser.scrooge_callsites.size' do MysqlUser.find(:first) end end - + test "should be able to retrieve a callsite form a given signature" do assert MysqlUser.find(:first).scrooged? assert_instance_of Scrooge::Callsite, MysqlUser.scrooge_callsite( first_callsite ) @@ -43,41 +43,41 @@ class ScroogeTest < ActiveRecord::TestCase test "should not flag records via Model.find with a custom :select requirement as scrooged" do assert !MysqlUser.find(:first, :select => 'user.Password' ).scrooged? end - + test "should be able to augment an existing callsite with attributes" do MysqlUser.find(:first) MysqlUser.scrooge_seen_column!( first_callsite, 'Password' ) assert MysqlUser.scrooge_callsite( first_callsite ).columns.include?( 'Password' ) end - + test "should be able to generate a SQL select snippet from a given set" do assert_equal MysqlUser.scrooge_select_sql( SimpleSet['Password','User','Host'] ), "`user`.User,`user`.Password,`user`.Host" end - + test "should be able to augment an existing callsite when attributes is referenced that we haven't seen yet" do user = MysqlUser.find(:first) MysqlUser.expects(:scrooge_seen_column!).times(2) user.Password user.Host end - + test "should not augment the callsite with known columns" do user = MysqlUser.find(:first) MysqlUser.expects(:augment_scrooge_callsite!).never user.User end - + test "should only fire after_initialize once" do # should not raise ActiveRecord::MissingAttributeError [:max_connections, :max_user_connections].each {|f| MysqlUser.find(:first).read_attribute(f)} end - + test "should make 3 queries to fetch same item twice due to reload and remembering" do assert_queries(3) {2.times {MysqlUser.find(:first).max_connections}} end - + def first_callsite MysqlUser.scrooge_callsites.to_a.flatten.first end - + end \ No newline at end of file