<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -20,7 +20,7 @@ module ThinkingSphinx
   module Version #:nodoc:
     Major = 0
     Minor = 9
-    Tiny  = 6
+    Tiny  = 7
     
     String = [Major, Minor, Tiny].join('.')
   end
@@ -67,6 +67,9 @@ module ThinkingSphinx
     @@deltas_enabled = value
   end
   
+  # Checks to see if MySQL will allow simplistic GROUP BY statements. If not,
+  # or if not using MySQL, this will return false.
+  # 
   def self.use_group_by_shortcut?
     ::ActiveRecord::ConnectionAdapters.constants.include?(&quot;MysqlAdapter&quot;) &amp;&amp;
     ::ActiveRecord::Base.connection.is_a?(</diff>
      <filename>lib/thinking_sphinx.rb</filename>
    </modified>
    <modified>
      <diff>@@ -122,16 +122,16 @@ module ThinkingSphinx
       options[:class_name]    = klass.name
       options[:foreign_key] ||= &quot;#{ref.name}_id&quot;
       
-      foreign_type = klass.connection.quote_column_name ref.options[:foreign_type]
+      quoted_foreign_type = klass.connection.quote_column_name ref.options[:foreign_type]
       case options[:conditions]
       when nil
-        options[:conditions] = &quot;::ts_join_alias::.#{foreign_type} = '#{klass.name}'&quot;
+        options[:conditions] = &quot;::ts_join_alias::.#{quoted_foreign_type} = '#{klass.name}'&quot;
       when Array
-        options[:conditions] &lt;&lt; &quot;::ts_join_alias::.#{foreign_type} = '#{klass.name}'&quot;
+        options[:conditions] &lt;&lt; &quot;::ts_join_alias::.#{quoted_foreign_type} = '#{klass.name}'&quot;
       when Hash
-        options[:conditions].merge!(foreign_type =&gt; klass.name)
+        options[:conditions].merge!(ref.options[:foreign_type] =&gt; klass.name)
       else
-        options[:conditions] &lt;&lt; &quot; AND ::ts_join_alias::.#{foreign_type} = '#{klass.name}'&quot;
+        options[:conditions] &lt;&lt; &quot; AND ::ts_join_alias::.#{quoted_foreign_type} = '#{klass.name}'&quot;
       end
       
       options</diff>
      <filename>lib/thinking_sphinx/association.rb</filename>
    </modified>
    <modified>
      <diff>@@ -23,6 +23,11 @@ Spec::Runner.configure do |config|
     # sphinx.start
   end
   
+  config.before :each do
+    NotAMock::CallRecorder.instance.reset
+    NotAMock::Stubber.instance.reset
+  end
+  
   config.after :all do
     # sphinx.stop
     </diff>
      <filename>spec/spec_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,6 @@
 require 'active_record'
+require 'active_record/connection_adapters/mysql_adapter'
+require 'active_record/connection_adapters/postgresql_adapter'
 require 'yaml'
 require 'spec/fixtures/models'
 </diff>
      <filename>spec/sphinx_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -17,6 +17,10 @@ describe &quot;ThinkingSphinx::ActiveRecord::Delta&quot; do
         :after_commit, [:toggle_delta]
       )
     end
+    
+    it &quot;should have an after_commit method by default&quot; do
+      Person.instance_methods.should include(&quot;after_commit&quot;)
+    end
   end
   
   describe &quot;save_with_after_commit_callback method&quot; do</diff>
      <filename>spec/unit/thinking_sphinx/active_record/delta_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -0,0 +1,63 @@
+require 'spec/spec_helper'
+
+describe &quot;ThinkingSphinx::ActiveRecord::Search&quot; do
+  it &quot;should add search_for_ids to ActiveRecord::Base&quot; do
+    ActiveRecord::Base.methods.should include(&quot;search_for_ids&quot;)
+  end
+  
+  it &quot;should add search_for_ids to ActiveRecord::Base&quot; do
+    ActiveRecord::Base.methods.should include(&quot;search&quot;)
+  end
+  
+  describe &quot;search_for_ids method&quot; do
+    before :each do
+      ThinkingSphinx::Search.stub_method(:search_for_ids =&gt; true)
+    end
+    
+    after :each do
+      ThinkingSphinx::Search.unstub_method(:search_for_ids)
+    end
+    
+    it &quot;should call ThinkingSphinx::Search#search_for_ids with the class option set&quot; do
+      Person.search_for_ids(&quot;search&quot;)
+      
+      ThinkingSphinx::Search.should have_received(:search_for_ids).with(
+        &quot;search&quot;, :class =&gt; Person
+      )
+    end
+    
+    it &quot;should override the class option&quot; do
+      Person.search_for_ids(&quot;search&quot;, :class =&gt; Friendship)
+      
+      ThinkingSphinx::Search.should have_received(:search_for_ids).with(
+        &quot;search&quot;, :class =&gt; Person
+      )
+    end
+  end
+  
+  describe &quot;search method&quot; do
+    before :each do
+      ThinkingSphinx::Search.stub_method(:search =&gt; true)
+    end
+    
+    after :each do
+      ThinkingSphinx::Search.unstub_method(:search)
+    end
+    
+    it &quot;should call ThinkingSphinx::Search#search with the class option set&quot; do
+      Person.search(&quot;search&quot;)
+      
+      ThinkingSphinx::Search.should have_received(:search).with(
+        &quot;search&quot;, :class =&gt; Person
+      )
+    end
+    
+    it &quot;should override the class option&quot; do
+      Person.search(&quot;search&quot;, :class =&gt; Friendship)
+      
+      ThinkingSphinx::Search.should have_received(:search).with(
+        &quot;search&quot;, :class =&gt; Person
+      )
+    end
+  end
+end
\ No newline at end of file</diff>
      <filename>spec/unit/thinking_sphinx/active_record/search_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -8,8 +8,9 @@ describe &quot;ThinkingSphinx::ActiveRecord&quot; do
       end
       
       TestModule::TestModel.stub_methods(
-        :before_save  =&gt; true,
-        :after_commit =&gt; true
+        :before_save    =&gt; true,
+        :after_commit   =&gt; true,
+        :after_destroy  =&gt; true
       )
       
       @index = ThinkingSphinx::Index.stub_instance(:delta? =&gt; false)
@@ -74,6 +75,20 @@ describe &quot;ThinkingSphinx::ActiveRecord&quot; do
       TestModule::TestModel.should_not have_received(:after_commit)
     end
     
+    it &quot;should add an after_destroy hook with delta indexing enabled&quot; do
+      @index.stub_method(:delta? =&gt; true)
+      
+      TestModule::TestModel.define_index do; end
+      
+      TestModule::TestModel.should have_received(:after_destroy).with(:toggle_deleted)
+    end
+    
+    it &quot;should add an after_destroy hook with delta indexing disabled&quot; do
+      TestModule::TestModel.define_index do; end
+      
+      TestModule::TestModel.should have_received(:after_destroy).with(:toggle_deleted)
+    end
+    
     it &quot;should return the new index&quot; do
       TestModule::TestModel.define_index.should == @index
     end
@@ -84,4 +99,59 @@ describe &quot;ThinkingSphinx::ActiveRecord&quot; do
       Person.to_crc32.should be_a_kind_of(Integer)
     end
   end
+  
+  describe &quot;toggle_deleted method&quot; do
+    before :each do
+      @configuration = ThinkingSphinx::Configuration.stub_instance(
+        :address  =&gt; &quot;an address&quot;,
+        :port     =&gt; 123
+      )
+      @client = Riddle::Client.stub_instance(:update =&gt; true)
+      @person = Person.new
+      
+      ThinkingSphinx::Configuration.stub_method(:new =&gt; @configuration)
+      Riddle::Client.stub_method(:new =&gt; @client)
+      Person.indexes.each { |index| index.stub_method(:delta? =&gt; false) }
+    end
+    
+    after :each do
+      ThinkingSphinx::Configuration.unstub_method(:new)
+      Riddle::Client.unstub_method(:new)
+      Person.indexes.each { |index| index.unstub_method(:delta?) }
+    end
+    
+    it &quot;should create a client using the Configuration's address and port&quot; do
+      @person.toggle_deleted
+      
+      Riddle::Client.should have_received(:new).with(
+        @configuration.address, @configuration.port
+      )
+    end
+    
+    it &quot;should update the core index's deleted flag&quot; do
+      @person.toggle_deleted
+      
+      @client.should have_received(:update).with(
+        &quot;person_core&quot;, [&quot;sphinx_deleted&quot;], {@person.id =&gt; 1}
+      )
+    end
+    
+    it &quot;should update the delta index's deleted flag if delta indexing is enabled&quot; do
+      Person.indexes.each { |index| index.stub_method(:delta? =&gt; true) }
+      
+      @person.toggle_deleted
+      
+      @client.should have_received(:update).with(
+        &quot;person_delta&quot;, [&quot;sphinx_deleted&quot;], {@person.id =&gt; 1}
+      )
+    end
+    
+    it &quot;shouldn't update the delta index if delta indexing is disabled&quot; do
+      @person.toggle_deleted
+      
+      @client.should_not have_received(:update).with(
+        &quot;person_delta&quot;, [&quot;sphinx_deleted&quot;], {@person.id =&gt; 1}
+      )
+    end
+  end
 end
\ No newline at end of file</diff>
      <filename>spec/unit/thinking_sphinx/active_record_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -0,0 +1,247 @@
+require 'spec/spec_helper'
+
+describe ThinkingSphinx::Association do
+  describe &quot;class-level children method&quot; do
+    before :each do
+      @normal_reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
+        :options =&gt; {:polymorphic =&gt; false}
+      )
+      @normal_association = ThinkingSphinx::Association.stub_instance
+      @poly_reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
+        :options        =&gt; {:polymorphic =&gt; true},
+        :macro          =&gt; :has_many,
+        :name           =&gt; &quot;polly&quot;,
+        :active_record  =&gt; &quot;AR&quot;
+      )
+      @non_poly_reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance
+      
+      Person.stub_method(:reflect_on_association =&gt; @normal_reflection)
+      ThinkingSphinx::Association.stub_methods(
+        :new                  =&gt; @normal_association,
+        :polymorphic_classes  =&gt; [Person, Person],
+        :casted_options       =&gt; {:casted =&gt; :options}
+      )
+      ::ActiveRecord::Reflection::AssociationReflection.stub_method(
+        :new =&gt; @non_poly_reflection
+      )
+    end
+    
+    it &quot;should return an empty array if no association exists&quot; do
+      Person.stub_method(:reflect_on_association =&gt; nil)
+      
+      ThinkingSphinx::Association.children(Person, :assoc).should == []
+    end
+    
+    it &quot;should return a single association instance in an array if assocation isn't polymorphic&quot; do
+      ThinkingSphinx::Association.children(Person, :assoc).should == [@normal_association]
+    end
+    
+    it &quot;should return multiple association instances for polymorphic associations&quot; do
+      Person.stub_method(:reflect_on_association =&gt; @poly_reflection)
+      
+      ThinkingSphinx::Association.children(Person, :assoc).should ==
+        [@normal_association, @normal_association]
+    end
+    
+    it &quot;should generate non-polymorphic 'casted' associations for each polymorphic possibility&quot; do
+      Person.stub_method(:reflect_on_association =&gt; @poly_reflection)
+      
+      ThinkingSphinx::Association.children(Person, :assoc)
+      
+      ThinkingSphinx::Association.should have_received(:casted_options).with(
+        Person, @poly_reflection
+      ).twice
+      
+      ::ActiveRecord::Reflection::AssociationReflection.should have_received(:new).with(
+        :has_many, :polly_Person, {:casted =&gt; :options}, &quot;AR&quot;
+      ).twice
+      
+      ThinkingSphinx::Association.should have_received(:new).with(
+        nil, @non_poly_reflection
+      ).twice
+    end
+  end
+  
+  describe &quot;instance-level children method&quot; do
+    it &quot;should return the children associations for the given association&quot; do
+      @reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
+        :klass =&gt; :klass
+      )
+      @association = ThinkingSphinx::Association.new(nil, @reflection)
+      ThinkingSphinx::Association.stub_method(:children =&gt; :result)
+      
+      @association.children(:assoc).should == :result
+      ThinkingSphinx::Association.should have_received(:children).with(:klass, :assoc, @association)
+    end
+  end
+  
+  describe &quot;join_to method&quot; do
+    before :each do
+      @parent_join = ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.stub_instance
+      @join = ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.stub_instance
+      @parent = ThinkingSphinx::Association.stub_instance(:join_to =&gt; true, :join =&gt; nil)
+      @base_join = Object.stub_instance(:joins =&gt; [:a, :b, :c])
+      
+      ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.stub_method(:new =&gt; @join)
+    end
+    
+    it &quot;should call the parent's join_to if parent has no join&quot; do
+      @assoc = ThinkingSphinx::Association.new(@parent, :ref)
+      
+      @assoc.join_to(@base_join)
+      
+      @parent.should have_received(:join_to).with(@base_join)
+    end
+    
+    it &quot;should not call the parent's join_to if it already has a join&quot; do
+      @assoc = ThinkingSphinx::Association.new(@parent, :ref)
+      @parent.stub_method(:join =&gt; @parent_join)
+      
+      @assoc.join_to(@base_join)
+      
+      @parent.should_not have_received(:join_to)
+    end
+    
+    it &quot;should define the join association with a JoinAssociation instance&quot; do
+      @assoc = ThinkingSphinx::Association.new(@parent, :ref)
+      
+      @assoc.join_to(@base_join).should == @join
+      @assoc.join.should == @join
+    end
+  end
+  
+  describe &quot;to_sql method&quot; do
+    before :each do
+      @reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
+        :klass =&gt; Person
+      )
+      @association = ThinkingSphinx::Association.new(nil, @reflection)
+      @parent = Object.stub_instance(:aliased_table_name =&gt; &quot;ALIAS TABLE NAME&quot;)
+      @join = ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.stub_instance(
+        :association_join =&gt; &quot;full association join SQL&quot;,
+        :parent           =&gt; @parent
+      )
+      @association.join = @join
+    end
+    
+    it &quot;should return the join's association join value&quot; do
+      @association.to_sql.should == &quot;full association join SQL&quot;
+    end
+    
+    it &quot;should replace ::ts_join_alias:: with the aliased table name&quot; do
+      @join.stub_method(:association_join =&gt; &quot;text with ::ts_join_alias:: gone&quot;)
+      
+      @association.to_sql.should == &quot;text with `ALIAS TABLE NAME` gone&quot;
+    end
+  end
+  
+  describe &quot;is_many? method&quot; do
+    before :each do
+      @parent = ThinkingSphinx::Association.stub_instance(
+        :is_many? =&gt; :parent_is_many
+      )
+      @reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
+        :macro =&gt; :has_many
+      )
+    end
+    
+    it &quot;should return true if association is either a has_many or a habtm&quot; do
+      association = ThinkingSphinx::Association.new(@parent, @reflection)
+      association.is_many?.should be_true
+      
+      @reflection.stub_method(:macro =&gt; :has_and_belongs_to_many)
+      association.is_many?.should be_true
+    end
+    
+    it &quot;should return the parent value if not a has many or habtm and there is a parent&quot; do
+      association = ThinkingSphinx::Association.new(@parent, @reflection)
+      @reflection.stub_method(:macro =&gt; :belongs_to)
+      association.is_many?.should == :parent_is_many
+    end
+    
+    it &quot;should return false if no parent and not a has many or habtm&quot; do
+      association = ThinkingSphinx::Association.new(nil, @reflection)
+      @reflection.stub_method(:macro =&gt; :belongs_to)
+      association.is_many?.should be_false
+    end
+  end
+  
+  describe &quot;ancestors method&quot; do
+    it &quot;should return an array of associations - including all parents&quot; do
+      parent = ThinkingSphinx::Association.stub_instance(:ancestors =&gt; [:all, :ancestors])
+      association = ThinkingSphinx::Association.new(parent, @reflection)
+      association.ancestors.should == [:all, :ancestors, association]
+    end
+  end
+  
+  describe &quot;polymorphic_classes method&quot; do
+    it &quot;should return all the polymorphic result types as classes&quot; do
+      Person.connection.stub_method(:select_all =&gt; [
+        {&quot;person_type&quot; =&gt; &quot;Person&quot;},
+        {&quot;person_type&quot; =&gt; &quot;Friendship&quot;}
+      ])
+      ref = Object.stub_instance(
+        :active_record  =&gt; Person,
+        :options        =&gt; {:foreign_type =&gt; &quot;person_type&quot;}
+      )
+      
+      ThinkingSphinx::Association.send(:polymorphic_classes, ref).should == [Person, Friendship]
+    end
+  end
+  
+  describe &quot;casted_options method&quot; do
+    before :each do
+      @options = {
+        :foreign_key  =&gt; &quot;thing_id&quot;,
+        :foreign_type =&gt; &quot;thing_type&quot;,
+        :polymorphic  =&gt; true
+      }
+      @reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
+        :options =&gt; @options
+      )
+    end
+    
+    it &quot;should return a new options set for a specific class&quot; do
+      ThinkingSphinx::Association.send(:casted_options, Person, @reflection).should == {
+        :polymorphic  =&gt; nil,
+        :class_name   =&gt; &quot;Person&quot;,
+        :foreign_key  =&gt; &quot;thing_id&quot;,
+        :foreign_type =&gt; &quot;thing_type&quot;,
+        :conditions   =&gt; &quot;::ts_join_alias::.`thing_type` = 'Person'&quot;
+      }
+    end
+        
+    it &quot;should append to existing Array of conditions&quot; do
+      @options[:conditions] = [&quot;first condition&quot;]
+      ThinkingSphinx::Association.send(:casted_options, Person, @reflection).should == {
+        :polymorphic  =&gt; nil,
+        :class_name   =&gt; &quot;Person&quot;,
+        :foreign_key  =&gt; &quot;thing_id&quot;,
+        :foreign_type =&gt; &quot;thing_type&quot;,
+        :conditions   =&gt; [&quot;first condition&quot;, &quot;::ts_join_alias::.`thing_type` = 'Person'&quot;]
+      }
+    end
+    
+    it &quot;should merge to an existing Hash of conditions&quot; do
+      @options[:conditions] = {&quot;field&quot; =&gt; &quot;value&quot;}
+      ThinkingSphinx::Association.send(:casted_options, Person, @reflection).should == {
+        :polymorphic  =&gt; nil,
+        :class_name   =&gt; &quot;Person&quot;,
+        :foreign_key  =&gt; &quot;thing_id&quot;,
+        :foreign_type =&gt; &quot;thing_type&quot;,
+        :conditions   =&gt; {&quot;field&quot; =&gt; &quot;value&quot;, &quot;thing_type&quot; =&gt; &quot;Person&quot;}
+      }
+    end
+    
+    it &quot;should append to an existing String of conditions&quot; do
+      @options[:conditions] = &quot;first condition&quot;
+      ThinkingSphinx::Association.send(:casted_options, Person, @reflection).should == {
+        :polymorphic  =&gt; nil,
+        :class_name   =&gt; &quot;Person&quot;,
+        :foreign_key  =&gt; &quot;thing_id&quot;,
+        :foreign_type =&gt; &quot;thing_type&quot;,
+        :conditions   =&gt; &quot;first condition AND ::ts_join_alias::.`thing_type` = 'Person'&quot;
+      }
+    end
+  end
+end
\ No newline at end of file</diff>
      <filename>spec/unit/thinking_sphinx/association_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,21 @@
 require 'spec/spec_helper'
 
 describe ThinkingSphinx::Attribute do
-  describe &quot;to_select_sql method&quot; do
+  describe '#initialize' do
+    it 'raises if no columns are provided so that configuration errors are easier to track down' do
+      lambda {
+        ThinkingSphinx::Attribute.new([])
+      }.should raise_error(RuntimeError)
+    end
+
+    it 'raises if an element of the columns param is an integer - as happens when you use id instead of :id - so that configuration errors are easier to track down' do
+      lambda {
+        ThinkingSphinx::Attribute.new([1234])
+      }.should raise_error(RuntimeError)
+    end
+  end
+  
+  describe &quot;to_select_sql method with MySQL&quot; do
     before :each do
       @index = Person.indexes.first
       @index.link!
@@ -36,6 +50,40 @@ describe ThinkingSphinx::Attribute do
     end
   end
   
+  describe &quot;to_select_sql method with PostgreSQL&quot; do
+    before :each do
+      @index = Person.indexes.first
+      Person.connection.class.stub_method(
+        :name =&gt; &quot;ActiveRecord::ConnectionAdapters::PostgreSQLAdapter&quot;
+      )
+      @index.link!
+    end
+    
+    it &quot;should concat with spaces if there's more than one non-integer column&quot; do
+      @index.attributes[0].to_select_sql.should match(/|| ' ' ||/)
+    end
+    
+    it &quot;should concat with spaces if there's more than one association for a non-integer column&quot; do
+      @index.attributes[1].to_select_sql.should match(/|| ' ' ||/)
+    end
+    
+    it &quot;should concat with commas if there's multiple integer columns&quot; do
+      @index.attributes[2].to_select_sql.should match(/|| ',' ||/)
+    end
+    
+    it &quot;should concat with commas if there's more than one association for an integer column&quot; do
+      @index.attributes[3].to_select_sql.should match(/|| ',' ||/)
+    end
+    
+    it &quot;should group with spaces if there's string columns from a has_many or has_and_belongs_to_many association&quot; do
+      @index.attributes[4].to_select_sql.should match(/array_to_string\(array_accum\(.+, ' '\)/)
+    end
+    
+    it &quot;should group with commas if there's integer columns from a has_many or has_and_belongs_to_many association&quot; do
+      @index.attributes[5].to_select_sql.should match(/array_to_string\(array_accum\(.+, ','\)/)
+    end
+  end
+  
   describe &quot;to_group_sql method&quot; do
     before :each do
       @attribute = ThinkingSphinx::Attribute.new([Object.stub_instance(:__stack =&gt; [])])
@@ -72,17 +120,237 @@ describe ThinkingSphinx::Attribute do
     end
   end
   
-  describe '#initialize' do
-    it 'raises if no columns are provided so that configuration errors are easier to track down' do
-      lambda {
-        ThinkingSphinx::Attribute.new([])
-      }.should raise_error(RuntimeError)
+  describe &quot;to_sphinx_clause method&quot; do
+    before :each do
+      @attribute = ThinkingSphinx::Attribute.new [Object.stub_instance(:__stack =&gt; [])]
+      @attribute.stub_method(:unique_name =&gt; &quot;unique name&quot;)
+    end
+    
+    it &quot;should use sql_attr_multi syntax for MVA attributes&quot; do
+      @attribute.stub_method(:type =&gt; :multi)
+      @attribute.to_sphinx_clause.should match(/^sql_attr_multi\s+= uint unique name from field$/)
+    end
+    
+    it &quot;should use sql_attr_timestamp syntax for datetime values&quot; do
+      @attribute.stub_method(:type =&gt; :datetime)
+      @attribute.to_sphinx_clause.should match(/^sql_attr_timestamp\s+= unique name$/)
+    end
+    
+    it &quot;should use sql_attr_str2ordinal for string values&quot; do
+      @attribute.stub_method(:type =&gt; :string)
+      @attribute.to_sphinx_clause.should match(/^sql_attr_str2ordinal\s+= unique name$/)
     end
+    
+    it &quot;should use sql_attr_float for float values&quot; do
+      @attribute.stub_method(:type =&gt; :float)
+      @attribute.to_sphinx_clause.should match(/^sql_attr_float\s+= unique name$/)
+    end
+    
+    it &quot;should use sql_attr_bool for boolean values&quot; do
+      @attribute.stub_method(:type =&gt; :boolean)
+      @attribute.to_sphinx_clause.should match(/^sql_attr_bool\s+= unique name$/)
+    end
+    
+    it &quot;should use sql_attr_uint for integer values&quot; do
+      @attribute.stub_method(:type =&gt; :integer)
+      @attribute.to_sphinx_clause.should match(/^sql_attr_uint\s+= unique name$/)
+    end
+    
+    it &quot;should assume integer for any other types&quot; do
+      @attribute.stub_method(:type =&gt; :unknown)
+      @attribute.to_sphinx_clause.should match(/^sql_attr_uint\s+= unique name$/)
+    end
+    
+  end
+  
+  describe &quot;unique_name method&quot; do
+    before :each do
+      @attribute = ThinkingSphinx::Attribute.new [
+        Object.stub_instance(:__stack =&gt; [], :__name =&gt; &quot;col_name&quot;)
+      ]
+    end
+    
+    it &quot;should use the alias if there is one&quot; do
+      @attribute.alias = &quot;alias&quot;
+      @attribute.unique_name.should == &quot;alias&quot;
+    end
+    
+    it &quot;should use the alias if there's multiple columns&quot; do
+      @attribute.columns &lt;&lt; Object.stub_instance(:__stack =&gt; [], :__name =&gt; &quot;col_name&quot;)
+      @attribute.unique_name.should be_nil
+      
+      @attribute.alias = &quot;alias&quot;
+      @attribute.unique_name.should == &quot;alias&quot;
+    end
+    
+    it &quot;should use the column name if there's no alias and just one column&quot; do
+      @attribute.unique_name.should == &quot;col_name&quot;
+    end
+  end
+  
+  describe &quot;column_with_prefix method&quot; do
+    before :each do
+      @attribute = ThinkingSphinx::Attribute.new [
+        ThinkingSphinx::Index::FauxColumn.new(:col_name)
+      ]
+      @attribute.columns.each { |col| @attribute.associations[col] = [] }
+      @attribute.model = Person
+      
+      @first_join   = Object.stub_instance(:aliased_table_name =&gt; &quot;tabular&quot;)
+      @second_join  = Object.stub_instance(:aliased_table_name =&gt; &quot;data&quot;)
+      
+      @first_assoc  = ThinkingSphinx::Association.stub_instance(:join =&gt; @first_join)
+      @second_assoc = ThinkingSphinx::Association.stub_instance(:join =&gt; @second_join)
+    end
+    
+    it &quot;should return the column name if the column is a string&quot; do
+      @attribute.columns = [ThinkingSphinx::Index::FauxColumn.new(&quot;string&quot;)]
+      @attribute.send(:column_with_prefix, @attribute.columns.first).should == &quot;string&quot;
+    end
+    
+    it &quot;should return the column with model's table prefix if there's no associations for the column&quot; do
+      @attribute.send(:column_with_prefix, @attribute.columns.first).should == &quot;`people`.`col_name`&quot;
+    end
+    
+    it &quot;should return the column with its join table prefix if an association exists&quot; do
+      column = @attribute.columns.first
+      @attribute.associations[column] = [@first_assoc]
+      @attribute.send(:column_with_prefix, column).should == &quot;`tabular`.`col_name`&quot;
+    end
+    
+    it &quot;should return multiple columns concatenated if more than one association exists&quot; do
+      column = @attribute.columns.first
+      @attribute.associations[column] = [@first_assoc, @second_assoc]
+      @attribute.send(:column_with_prefix, column).should == &quot;`tabular`.`col_name`, `data`.`col_name`&quot;
+    end
+  end
+  
+  describe &quot;is_many? method&quot; do
+    before :each do
+      @assoc_a = Object.stub_instance(:is_many? =&gt; true)
+      @assoc_b = Object.stub_instance(:is_many? =&gt; true)
+      @assoc_c = Object.stub_instance(:is_many? =&gt; true)
+      
+      @attribute = ThinkingSphinx::Attribute.new(
+        [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
+      )
+      @attribute.associations = {
+        :a =&gt; @assoc_a, :b =&gt; @assoc_b, :c =&gt; @assoc_c
+      }
+    end
+    
+    it &quot;should return true if all associations return true to is_many?&quot; do
+      @attribute.send(:is_many?).should be_true
+    end
+    
+    it &quot;should return true if one association returns true to is_many?&quot; do
+      @assoc_b.stub_method(:is_many? =&gt; false)
+      @assoc_c.stub_method(:is_many? =&gt; false)
+      
+      @attribute.send(:is_many?).should be_true
+    end
+    
+    it &quot;should return false if all associations return false to is_many?&quot; do
+      @assoc_a.stub_method(:is_many? =&gt; false)
+      @assoc_b.stub_method(:is_many? =&gt; false)
+      @assoc_c.stub_method(:is_many? =&gt; false)
+      
+      @attribute.send(:is_many?).should be_false
+    end
+  end
+  
+  describe &quot;is_string? method&quot; do
+    before :each do
+      @col_a = ThinkingSphinx::Index::FauxColumn.new(&quot;a&quot;)
+      @col_b = ThinkingSphinx::Index::FauxColumn.new(&quot;b&quot;)
+      @col_c = ThinkingSphinx::Index::FauxColumn.new(&quot;c&quot;)
 
-    it 'raises if an element of the columns param is an integer - as happens when you use id instead of :id - so that configuration errors are easier to track down' do
-      lambda {
-        ThinkingSphinx::Attribute.new([1234])
-      }.should raise_error(RuntimeError)
+      @attribute = ThinkingSphinx::Attribute.new(
+        [@col_a, @col_b, @col_c]
+      )
+    end
+    
+    it &quot;should return true if all columns return true to is_string?&quot; do
+      @attribute.send(:is_string?).should be_true
+    end
+    
+    it &quot;should return false if one column returns true to is_string?&quot; do
+      @col_a.send(:instance_variable_set, :@name, :a)
+      @attribute.send(:is_string?).should be_false
+    end
+    
+    it &quot;should return false if all columns return false to is_string?&quot; do
+      @col_a.send(:instance_variable_set, :@name, :a)
+      @col_b.send(:instance_variable_set, :@name, :b)
+      @col_c.send(:instance_variable_set, :@name, :c)
+      @attribute.send(:is_string?).should be_false
+    end
+  end
+  
+  describe &quot;type method&quot; do
+    before :each do
+      @column = ThinkingSphinx::Index::FauxColumn.new(:col_name)
+      @attribute = ThinkingSphinx::Attribute.new([@column])
+      @attribute.model = Person
+      @attribute.stub_method(:is_many? =&gt; false)
+    end
+    
+    it &quot;should return :multi if is_many? is true&quot; do
+      @attribute.stub_method(:is_many? =&gt; true)
+      @attribute.send(:type).should == :multi
+    end
+    
+    it &quot;should return :string if there's more than one association&quot; do
+      @attribute.associations = {:a =&gt; :assoc, :b =&gt; :assoc}
+      @attribute.send(:type).should == :string
+    end
+    
+    it &quot;should return the column type from the database if not :multi or more than one association&quot; do
+      @column.send(:instance_variable_set, :@name, &quot;birthday&quot;)
+      @attribute.send(:type).should == :datetime
+      
+      @attribute.send(:instance_variable_set, :@type, nil)
+      @column.send(:instance_variable_set, :@name, &quot;first_name&quot;)
+      @attribute.send(:type).should == :string
+      
+      @attribute.send(:instance_variable_set, :@type, nil)
+      @column.send(:instance_variable_set, :@name, &quot;id&quot;)
+      @attribute.send(:type).should == :integer
+    end
+  end
+  
+  describe &quot;all_ints? method&quot; do
+    it &quot;should return true if all columns are integers&quot; do
+      attribute = ThinkingSphinx::Attribute.new(
+        [ ThinkingSphinx::Index::FauxColumn.new(:id),
+          ThinkingSphinx::Index::FauxColumn.new(:team_id) ]
+      )
+      attribute.model = Person
+      attribute.columns.each { |col| attribute.associations[col] = [] }
+      
+      attribute.send(:all_ints?).should be_true
+    end
+    
+    it &quot;should return false if only some columns are integers&quot; do
+      attribute = ThinkingSphinx::Attribute.new(
+        [ ThinkingSphinx::Index::FauxColumn.new(:id),
+          ThinkingSphinx::Index::FauxColumn.new(:first_name) ]
+      )
+      attribute.model = Person
+      attribute.columns.each { |col| attribute.associations[col] = [] }
+      
+      attribute.send(:all_ints?).should be_false
+    end
+    
+    it &quot;should return false if no columns are integers&quot; do
+      attribute = ThinkingSphinx::Attribute.new(
+        [ ThinkingSphinx::Index::FauxColumn.new(:first_name),
+          ThinkingSphinx::Index::FauxColumn.new(:last_name) ]
+      )
+      attribute.model = Person
+      attribute.columns.each { |col| attribute.associations[col] = [] }
+      
+      attribute.send(:all_ints?).should be_false
     end
   end
 end
\ No newline at end of file</diff>
      <filename>spec/unit/thinking_sphinx/attribute_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,44 @@
 require 'spec/spec_helper'
 
 describe ThinkingSphinx::Configuration do
+  describe &quot;environment class method&quot; do
+    before :each do
+      ThinkingSphinx::Configuration.send(:class_variable_set, :@@environment, nil)
+      
+      ENV[&quot;RAILS_ENV&quot;]  = nil
+      ENV[&quot;MERB_ENV&quot;]   = nil
+    end
+    
+    it &quot;should use the Merb environment value if set&quot; do
+      unless defined?(Merb)
+        module Merb; end
+      end
+      
+      ThinkingSphinx::Configuration.stub_method(:defined? =&gt; true)
+      ENV[&quot;MERB_ENV&quot;] = &quot;merb_production&quot;
+      ThinkingSphinx::Configuration.environment.should == &quot;merb_production&quot;
+      
+      Object.send(:remove_const, :Merb)
+    end
+    
+    it &quot;should use the Rails environment value if set&quot; do
+      ENV[&quot;RAILS_ENV&quot;] = &quot;rails_production&quot;
+      ThinkingSphinx::Configuration.environment.should == &quot;rails_production&quot;
+    end
+    
+    it &quot;should default to development&quot; do
+      ThinkingSphinx::Configuration.environment.should == &quot;development&quot;
+    end
+  end
+  
+  describe &quot;environment instance method&quot; do
+    it &quot;should return the class method&quot; do
+      ThinkingSphinx::Configuration.stub_method(:environment =&gt; &quot;spec&quot;)
+      ThinkingSphinx::Configuration.new.environment.should == &quot;spec&quot;
+      ThinkingSphinx::Configuration.should have_received(:environment)
+    end
+  end
+  
   describe &quot;build method&quot; do
     before :each do
       @config = ThinkingSphinx::Configuration.new
@@ -158,6 +196,44 @@ describe ThinkingSphinx::Configuration do
     end
   end
   
+  describe &quot;load_models method&quot; do
+    it &quot;should have some specs&quot;
+  end
+  
+  describe &quot;parse_config method&quot; do
+    before :each do
+      @settings = {
+        &quot;development&quot; =&gt; {
+          &quot;config_file&quot;       =&gt; &quot;my_conf_file.conf&quot;,
+          &quot;searchd_log_file&quot;  =&gt; &quot;searchd_log_file.log&quot;,
+          &quot;query_log_file&quot;    =&gt; &quot;query_log_file.log&quot;,
+          &quot;pid_file&quot;          =&gt; &quot;pid_file.pid&quot;,
+          &quot;searchd_file_path&quot; =&gt; &quot;searchd/file/path&quot;,
+          &quot;address&quot;           =&gt; &quot;127.0.0.1&quot;,
+          &quot;port&quot;              =&gt; 3333,
+          &quot;allow_star&quot;        =&gt; true,
+          &quot;mem_limit&quot;         =&gt; &quot;128M&quot;,
+          &quot;max_matches&quot;       =&gt; 1001,
+          &quot;morphology&quot;        =&gt; &quot;stem_ru&quot;,
+          &quot;charset_type&quot;      =&gt; &quot;latin1&quot;,
+          &quot;charset_table&quot;     =&gt; &quot;table&quot;,
+          &quot;ignore_chars&quot;      =&gt; &quot;e&quot;
+        }
+      }
+      # puts YAML.dump(settings)
+      open(&quot;#{RAILS_ROOT}/config/sphinx.yml&quot;, &quot;w&quot;) do |f|
+        f.write  YAML.dump(@settings)
+      end
+    end
+    
+    it &quot;should use the accessors to set the configuration values&quot; do
+      config = ThinkingSphinx::Configuration.new
+      @settings[&quot;development&quot;].each do |key, value|
+        config.send(key).should == value
+      end
+    end
+  end
+  
   describe &quot;core_index_for_model method&quot; do
     before :each do
       @config = ThinkingSphinx::Configuration.new
@@ -355,4 +431,8 @@ describe ThinkingSphinx::Configuration do
       )
     end
   end
+  
+  describe &quot;create_array_accum method&quot; do
+    it &quot;should create the array_accum method on PostgreSQL&quot;
+  end
 end
\ No newline at end of file</diff>
      <filename>spec/unit/thinking_sphinx/configuration_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,21 @@
 require 'spec/spec_helper'
 
 describe ThinkingSphinx::Field do
-  describe &quot;to_select_sql method&quot; do
+  describe '#initialize' do
+    it 'raises if no columns are provided so that configuration errors are easier to track down' do
+      lambda {
+        ThinkingSphinx::Field.new([])
+      }.should raise_error(RuntimeError)
+    end
+
+    it 'raises if an element of the columns param is an integer - as happens when you use id instead of :id - so that configuration errors are easier to track down' do
+      lambda {
+        ThinkingSphinx::Field.new([1234])
+      }.should raise_error(RuntimeError)
+    end
+  end
+  
+  describe &quot;to_select_sql method with MySQL&quot; do
     before :each do
       @index = Person.indexes.first
       @index.link!
@@ -20,6 +34,28 @@ describe ThinkingSphinx::Field do
     end
   end
   
+  describe &quot;to_select_sql method with PostgreSQL&quot; do
+    before :each do
+      @index = Person.indexes.first
+      Person.connection.class.stub_method(
+        :name =&gt; &quot;ActiveRecord::ConnectionAdapters::PostgreSQLAdapter&quot;
+      )
+      @index.link!
+    end
+    
+    it &quot;should concat with spaces if there are multiple columns&quot; do
+      @index.fields.first.to_select_sql.should match(/|| ' ' ||/)
+    end
+    
+    it &quot;should concat with spaces if a column has more than one association&quot; do
+      @index.fields[1].to_select_sql.should match(/|| ' ' ||/)
+    end
+    
+    it &quot;should group if any association for any column is a has_many or has_and_belongs_to_many&quot; do
+      @index.fields[2].to_select_sql.should match(/array_to_string\(array_accum\(/)
+    end
+  end
+  
   describe &quot;to_group_sql method&quot; do
     before :each do
       @field = ThinkingSphinx::Field.new([Object.stub_instance(:__stack =&gt; [])])
@@ -44,26 +80,33 @@ describe ThinkingSphinx::Field do
       @field.stub_method(:column_with_prefix =&gt; 'hello')
       @field.to_group_sql.should be_a_kind_of(Array)
     end
+  end
+  
+  describe &quot;unique_name method&quot; do
+    before :each do
+      @field = ThinkingSphinx::Field.new [
+        Object.stub_instance(:__stack =&gt; [], :__name =&gt; &quot;col_name&quot;)
+      ]
+    end
     
-    after :each do
-      ThinkingSphinx.unstub_method(:use_group_by_shortcut?)
+    it &quot;should use the alias if there is one&quot; do
+      @field.alias = &quot;alias&quot;
+      @field.unique_name.should == &quot;alias&quot;
     end
-  end
-
-  describe '#initialize' do
-    it 'raises if no columns are provided so that configuration errors are easier to track down' do
-      lambda {
-        ThinkingSphinx::Field.new([])
-      }.should raise_error(RuntimeError)
+    
+    it &quot;should use the alias if there's multiple columns&quot; do
+      @field.columns &lt;&lt; Object.stub_instance(:__stack =&gt; [], :__name =&gt; &quot;col_name&quot;)
+      @field.unique_name.should be_nil
+      
+      @field.alias = &quot;alias&quot;
+      @field.unique_name.should == &quot;alias&quot;
     end
-
-    it 'raises if an element of the columns param is an integer - as happens when you use id instead of :id - so that configuration errors are easier to track down' do
-      lambda {
-        ThinkingSphinx::Field.new([1234])
-      }.should raise_error(RuntimeError)
+    
+    it &quot;should use the column name if there's no alias and just one column&quot; do
+      @field.unique_name.should == &quot;col_name&quot;
     end
   end
-  
+
   describe &quot;prefixes method&quot; do
     it &quot;should default to false&quot; do
       @field = ThinkingSphinx::Field.new([Object.stub_instance(:__stack =&gt; [])])
@@ -91,4 +134,82 @@ describe ThinkingSphinx::Field do
       @field.infixes.should be_true
     end
   end
+  
+  describe &quot;quote_column_name method&quot; do
+    it &quot;should delegate the call to the model's connection&quot; do
+      @field = ThinkingSphinx::Field.new [
+        ThinkingSphinx::Index::FauxColumn.new(:col_name)
+      ]
+      @field.model = Person
+      Person.connection.stub_method(:quote_column_name =&gt; &quot;quoted!&quot;)
+      
+      @field.send(:quote_column, &quot;blah&quot;).should == &quot;quoted!&quot;
+    end
+  end
+  
+  describe &quot;column_with_prefix method&quot; do
+    before :each do
+      @field = ThinkingSphinx::Field.new [
+        ThinkingSphinx::Index::FauxColumn.new(:col_name)
+      ]
+      @field.columns.each { |col| @field.associations[col] = [] }
+      @field.model = Person
+      
+      @first_join   = Object.stub_instance(:aliased_table_name =&gt; &quot;tabular&quot;)
+      @second_join  = Object.stub_instance(:aliased_table_name =&gt; &quot;data&quot;)
+      
+      @first_assoc  = ThinkingSphinx::Association.stub_instance(:join =&gt; @first_join)
+      @second_assoc = ThinkingSphinx::Association.stub_instance(:join =&gt; @second_join)
+    end
+    
+    it &quot;should return the column with model's table prefix if there's no associations for the column&quot; do
+      @field.send(:column_with_prefix, @field.columns.first).should == &quot;`people`.`col_name`&quot;
+    end
+    
+    it &quot;should return the column with its join table prefix if an association exists&quot; do
+      column = @field.columns.first
+      @field.associations[column] = [@first_assoc]
+      @field.send(:column_with_prefix, column).should == &quot;`tabular`.`col_name`&quot;
+    end
+    
+    it &quot;should return multiple columns concatenated if more than one association exists&quot; do
+      column = @field.columns.first
+      @field.associations[column] = [@first_assoc, @second_assoc]
+      @field.send(:column_with_prefix, column).should == &quot;`tabular`.`col_name`, `data`.`col_name`&quot;
+    end
+  end
+  
+  describe &quot;is_many? method&quot; do
+    before :each do
+      @assoc_a = Object.stub_instance(:is_many? =&gt; true)
+      @assoc_b = Object.stub_instance(:is_many? =&gt; true)
+      @assoc_c = Object.stub_instance(:is_many? =&gt; true)
+      
+      @field = ThinkingSphinx::Field.new(
+        [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
+      )
+      @field.associations = {
+        :a =&gt; @assoc_a, :b =&gt; @assoc_b, :c =&gt; @assoc_c
+      }
+    end
+    
+    it &quot;should return true if all associations return true to is_many?&quot; do
+      @field.send(:is_many?).should be_true
+    end
+    
+    it &quot;should return true if one association returns true to is_many?&quot; do
+      @assoc_b.stub_method(:is_many? =&gt; false)
+      @assoc_c.stub_method(:is_many? =&gt; false)
+      
+      @field.send(:is_many?).should be_true
+    end
+    
+    it &quot;should return false if all associations return false to is_many?&quot; do
+      @assoc_a.stub_method(:is_many? =&gt; false)
+      @assoc_b.stub_method(:is_many? =&gt; false)
+      @assoc_c.stub_method(:is_many? =&gt; false)
+      
+      @field.send(:is_many?).should be_false
+    end
+  end
 end</diff>
      <filename>spec/unit/thinking_sphinx/field_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -78,5 +78,30 @@ describe ThinkingSphinx do
       
       ThinkingSphinx.use_group_by_shortcut?.should be_false
     end
+    
+    describe &quot;if not using MySQL&quot; do
+      before :each do
+        @connection = ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.stub_instance(
+          :select_all =&gt; true
+        )
+        ::ActiveRecord::Base.stub_method(
+          :connection =&gt; @connection
+        )
+      end
+      
+      after :each do
+        ::ActiveRecord::Base.unstub_method(:connection)
+      end
+    
+      it &quot;should return false&quot; do
+        ThinkingSphinx.use_group_by_shortcut?.should be_false
+      end
+    
+      it &quot;should not call select_all&quot; do
+        ThinkingSphinx.use_group_by_shortcut?
+        
+        @connection.should_not have_received(:select_all)
+      end
+    end
   end
 end
\ No newline at end of file</diff>
      <filename>spec/unit/thinking_sphinx_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,6 @@
 Gem::Specification.new do |s|
   s.name              = &quot;thinking-sphinx&quot;
-  s.version           = &quot;0.9.6&quot;
+  s.version           = &quot;0.9.7&quot;
   s.summary           = &quot;A concise and easy-to-use Ruby library that connects ActiveRecord to the Sphinx search daemon, managing configuration, indexing and searching.&quot;
   s.description       = &quot;A concise and easy-to-use Ruby library that connects ActiveRecord to the Sphinx search daemon, managing configuration, indexing and searching.&quot;
   s.author            = &quot;Pat Allan&quot;</diff>
      <filename>thinking-sphinx.gemspec</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>92450ffc2f6344d5822c4fcc3d9d77fcddde35b7</id>
    </parent>
  </parents>
  <author>
    <name>Pat Allan</name>
    <email>pat@freelancing-gods.com</email>
  </author>
  <url>http://github.com/xaviershay/thinking-sphinx/commit/352436d0e3cf74ff770f3dbf0ad3528394689252</url>
  <id>352436d0e3cf74ff770f3dbf0ad3528394689252</id>
  <committed-date>2008-06-07T14:00:22-07:00</committed-date>
  <authored-date>2008-06-07T14:00:22-07:00</authored-date>
  <message>Adding a lot more specs, including some tweaks</message>
  <tree>2176adc80778a141b34e47d7ddeae0d40402c5fe</tree>
  <committer>
    <name>Pat Allan</name>
    <email>pat@freelancing-gods.com</email>
  </committer>
</commit>
