diff --git a/TODO b/TODO index be1df1e..8b1f773 100644 --- a/TODO +++ b/TODO @@ -1,99 +1,13 @@ * Rails 3.1 Implementation - /Users/kencollins/Repositories/rails/activerecord/lib/active_record/reflection.rb - [24, 159, 331] - /Users/kencollins/Repositories/rails/activerecord/lib/active_record/associations.rb - [154, 1171] - /Users/kencollins/Repositories/rails/activerecord/lib/active_record/associations/builder/association.rb - [] - /Users/kencollins/Repositories/rails/activerecord/lib/active_record/associations/builder/collection_association.rb - [] - /Users/kencollins/Repositories/rails/activerecord/lib/active_record/associations/builder/has_many.rb - - /Users/kencollins/Repositories/rails/activerecord/lib/active_record/associations/has_many_association.rb - - /Users/kencollins/Repositories/rails/activerecord/lib/active_record/associations/collection_association.rb - [370] - /Users/kencollins/Repositories/rails/activerecord/lib/active_record/associations/association.rb - [97] - /Users/kencollins/Repositories/rails/activerecord/lib/active_record/associations/association_scope.rb - [48] - - Notes: - - >> User.reflections[:boxes] - => #:columns, :readonly=>false, :order=>"columns.position, boxes.position", :extend=>[UserBoxesAssociationExtension]}, @active_record=User(14 columns), @plural_name="boxes", @collection=true> - >> User.reflections[:boxes].source_reflection - => #"position", :extend=>[]}, @active_record=Column(3 columns), @plural_name="boxes", @collection=true> - >> User.reflections[:boxes].through_reflection - => #"position", :extend=>[]}, @active_record=User(14 columns), @plural_name="columns", @collection=true, @class_name="Column", @klass=Column(3 columns)> - >> User.reflections[:boxes].source_reflection_names - => [:box, :boxes] - >> User.reflections[:boxes].source_options - => {:order=>"position", :extend=>[]} - >> User.reflections[:boxes].through_options - => {:order=>"position", :extend=>[]} - >> User.reflections[:boxes].class_name - => "Box" - - - >> User.reflections[:columns].primary_key_column - => # - >> User.reflections[:columns].association_foreign_key - => "column_id" - >> User.reflections[:columns].association_primary_key - => "id" - >> User.reflections[:columns].active_record_primary_key - => "id" - >> User.reflections[:columns].active_record - => User(14 columns) - - - equalities = wheres.grep(Arel::Nodes::Equality) - - >> ActiveRecord::Associations::AssociationScope.new(User.first.association(:columns)).scope.where_values - User Load (0.5ms) SELECT "users".* FROM "users" LIMIT 1 - => [#, name="user_id">, @right=8>] - - >> ActiveRecord::Associations::AssociationScope.new(User.first.association(:columns)).send(:construct_tables) - User Load (0.4ms) SELECT "users".* FROM "users" LIMIT 1 - => [#] - - >> ActiveRecord::Associations::AssociationScope.new(User.first.association(:columns)) - User Load (0.4ms) SELECT "users".* FROM "users" LIMIT 1 - Column Load (0.7ms) SELECT "columns".* FROM "columns" WHERE "columns"."user_id" = 8 ORDER BY position - => #"position", :extend=>[]}, @active_record=User(14 columns), @plural_name="columns", @collection=true, @class_name="Column", @klass=Column(3 columns), @foreign_key="user_id", @active_record_primary_key="id", @type=nil, @table_name="columns", @association_foreign_key="column_id">, @owner=#, @updated=false, @loaded=false, @association_scope=nil, @proxy=[#, #], @stale_state=nil>, @alias_tracker=#> - - >> User.first.columns.unscoped { Column.where(:position => 99) } - User Load (0.4ms) SELECT "users".* FROM "users" LIMIT 1 - Column Load (0.9ms) SELECT "columns".* FROM "columns" WHERE "columns"."position" = 99 - => [] - - >> User.first.columns.unscoped { Column.where(:user_id => [1,2,3]) } - User Load (0.4ms) SELECT "users".* FROM "users" LIMIT 1 - Column Load (0.9ms) SELECT "columns".* FROM "columns" WHERE "columns"."user_id" IN (1, 2, 3) - => [#, #, #, #, #, #] - - >> User.reflections[:columns].association_class - => ActiveRecord::Associations::HasManyAssociation - - >> User.reflections[:columns].association_foreign_key - => "column_id" - - >> User.reflect_on_all_associations(:has_many).detect { |a| a.name == :columns } - => #"position", :extend=>[]}, @active_record=User(14 columns), @plural_name="columns", @collection=true, @class_name="Column", @klass=Column(3 columns), @foreign_key="user_id", @active_record_primary_key="id", @type=nil, @table_name="columns", @association_foreign_key="column_id"> + * Kill &block stuff. - >> User.reflections[:columns] - => #"position", :extend=>[]}, @active_record=User(14 columns), @plural_name="columns", @collection=true, @class_name="Column", @klass=Column(3 columns), @foreign_key="user_id", @active_record_primary_key="id", @type=nil> + * Make association conditions use pure SQL. Avoid 100s of IDs. - >> User.reflect_on_association(:columns) - => #"position", :extend=>[]}, @active_record=User(14 columns), @plural_name="columns", @collection=true, @class_name="Column", @klass=Column(3 columns), @foreign_key="user_id", @active_record_primary_key="id", @type=nil> - - >> User.first.association(:columns) - => #"position", :extend=>[]}, @active_record=User(14 columns), @plural_name="columns", @collection=true, @class_name="Column", @klass=Column(3 columns), @foreign_key="user_id", @active_record_primary_key="id", @type=nil>, @owner=#, @updated=false, @loaded=false, @association_scope=nil, @proxy=[#, #], @stale_state=nil> - - + * Try out altering the #association_scope wheres after the fact vs a monkey patched version. * Use appraisal for rails dep testing. https://github.com/thoughtbot/appraisal -* Redo for rails 3.1 tests. - -* Kill &block stuff. - -* Make association conditions use pure SQL. Avoid 100's of IDs. - - diff --git a/lib/grouped_scope.rb b/lib/grouped_scope.rb index d337040..80bb055 100644 --- a/lib/grouped_scope.rb +++ b/lib/grouped_scope.rb @@ -4,6 +4,7 @@ require 'grouped_scope/arish/reflection' require 'grouped_scope/arish/associations/collection_association' +require 'grouped_scope/arish/associations/builder/grouped_association' require 'grouped_scope/arish/associations/builder/grouped_collection_association' require 'grouped_scope/arish/associations/association_scope' require 'grouped_scope/arish/relation/predicate_builer' diff --git a/lib/grouped_scope/arish/associations/builder/grouped_association.rb b/lib/grouped_scope/arish/associations/builder/grouped_association.rb new file mode 100644 index 0000000..f8be83f --- /dev/null +++ b/lib/grouped_scope/arish/associations/builder/grouped_association.rb @@ -0,0 +1,50 @@ +module GroupedScope + module Arish + module Associations + module Builder + class GroupedAssociation + + attr_reader :model, :ungrouped_name, :ungrouped_reflection, :grouped_name, :grouped_options + + def self.build(model, *association_names) + association_names.each { |ungrouped_name| new(model, ungrouped_name).build } + end + + def initialize(model, ungrouped_name) + @model = model + @ungrouped_name = ungrouped_name + @ungrouped_reflection = find_ungrouped_reflection + @grouped_name = :"grouped_scope_#{ungrouped_name}" + @grouped_options = copy_ungrouped_reflection_options + end + + def build + model.send(ungrouped_reflection.macro, grouped_name, grouped_options).tap do |grouped_reflection| + grouped_reflection.grouped_scope = true + model.grouped_reflections = model.grouped_reflections.merge(ungrouped_name => grouped_reflection) + define_grouped_scope_reader(model) + end + end + + + private + + def define_grouped_scope_reader(model) + model.send(:define_method, :group) do + @group ||= GroupedScope::SelfGroupping.new(self) + end + end + + def find_ungrouped_reflection + model.reflections[ungrouped_name] + end + + def copy_ungrouped_reflection_options + ungrouped_reflection.options.dup + end + + end + end + end + end +end diff --git a/lib/grouped_scope/arish/associations/builder/grouped_collection_association.rb b/lib/grouped_scope/arish/associations/builder/grouped_collection_association.rb index 08f2d04..0cdf58c 100644 --- a/lib/grouped_scope/arish/associations/builder/grouped_collection_association.rb +++ b/lib/grouped_scope/arish/associations/builder/grouped_collection_association.rb @@ -2,48 +2,27 @@ module GroupedScope module Arish module Associations module Builder - class GroupedCollectionAssociation + class GroupedCollectionAssociation < GroupedAssociation - class << self - - def build(model, *association_names) - association_names.each do |name| - ungrouped_reflection = find_ungrouped_reflection(model, name) - options = ungrouped_reflection_options(ungrouped_reflection) - grouped_reflection = model.send ungrouped_reflection.macro, :"grouped_scope_#{name}", options - grouped_reflection.grouped_scope = true - model.grouped_reflections = model.grouped_reflections.merge(name => grouped_reflection) - end - define_grouped_scope_reader(model) - end - - private - - def define_grouped_scope_reader(model) - model.send(:define_method, :group) do - @group ||= GroupedScope::SelfGroupping.new(self) - end - end - - def find_ungrouped_reflection(model, name) - reflection = model.reflections[name.to_sym] - if reflection.blank? || [:has_many, :has_and_belongs_to_many].exclude?(reflection.macro) - msg = "Cannot create a group scope for #{name.inspect}. Either the reflection is blank or not supported. " + - "Make sure to call grouped_scope after the association you are trying to extend has been defined." - raise ArgumentError, msg - end - reflection + private + + def find_ungrouped_reflection + reflection = model.reflections[ungrouped_name] + if reflection.blank? || [:has_many, :has_and_belongs_to_many].exclude?(reflection.macro) + msg = "Cannot create a group scope for #{ungrouped_name.inspect}. Either the reflection is blank or not supported. " + + "Make sure to call grouped_scope after the association you are trying to extend has been defined." + raise ArgumentError, msg end - - def ungrouped_reflection_options(ungrouped_reflection) - ungrouped_reflection.options.dup.tap do |options| - options[:class_name] = ungrouped_reflection.class_name - if ungrouped_reflection.source_reflection && options[:source].blank? - options[:source] = ungrouped_reflection.source_reflection.name - end + reflection + end + + def copy_ungrouped_reflection_options + ungrouped_reflection.options.dup.tap do |options| + options[:class_name] = ungrouped_reflection.class_name + if ungrouped_reflection.source_reflection && options[:source].blank? + options[:source] = ungrouped_reflection.source_reflection.name end end - end end