<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>examples/ap.multi</filename>
    </added>
    <added>
      <filename>test/integration/app/db/migrate/007_add_lat_and_long_to_address.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,4 +1,6 @@
 
+v1.5.3. 90% test coverage. Support multiple spelling dictionaries per machine (configurable in the .base file).
+
 v1.5.2. Fix association reloading issue; support float attributes on Sphinx 0.9.8; fix date range filters; import and update sample app (Mark Lane); start a comprehensive integration suite.
 
 v1.5.1. Various bugfixes.</diff>
      <filename>CHANGELOG</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,4 @@
 
-* Support multiple spelling dictionaries per machine
 * Finish unifying filters and textfields
 * Support exclude filters
 * Make sure filters can be set to nil</diff>
      <filename>TODO</filename>
    </modified>
    <modified>
      <diff>@@ -29,6 +29,8 @@ searchd
 client
 {
   # Client options
+  # Name of the Aspell dictionary (two letters max)
+  dictionary_name = ap
   # How your application connects to the search daemon (not necessarily the same as above)
   server_host = localhost
   server_port = 3312</diff>
      <filename>examples/default.base</filename>
    </modified>
    <modified>
      <diff>@@ -65,7 +65,7 @@ module Ultrasphinx
       def global_header
         [&quot;\n# Auto-generated at #{Time.now}.&quot;,
          &quot;# Hand modifications will be overwritten.&quot;,
-         &quot;# #{BASE_PATH}&quot;,
+         &quot;# #{BASE_PATH}\n&quot;,
          INDEXER_SETTINGS._to_conf_string('indexer'),
          DAEMON_SETTINGS._to_conf_string(&quot;searchd&quot;)]
       end      
@@ -137,7 +137,6 @@ module Ultrasphinx
       
       
       def build_query(klass, column_strings, join_strings, condition_strings)
-
         [&quot;sql_query =&quot;, 
           &quot;SELECT&quot;, 
           column_strings.sort_by do |string| 
@@ -147,9 +146,7 @@ module Ultrasphinx
           &quot;FROM #{klass.table_name}&quot;,
           join_strings.uniq,
           &quot;WHERE #{klass.table_name}.#{klass.primary_key} &gt;= $start AND #{klass.table_name}.#{klass.primary_key} &lt;= $end&quot;,
-          condition_strings.uniq.map do |condition| 
-            &quot;AND #{condition}&quot;
-          end,
+          condition_strings.uniq.map {|condition| &quot;AND #{condition}&quot; },
           ADAPTER_SQL_FUNCTIONS[ADAPTER]['group_by']
         ].flatten.join(&quot; &quot;)
       end
@@ -253,10 +250,9 @@ module Ultrasphinx
         column_strings &lt;&lt; fields.cast(source_string, as)
         remaining_columns.delete(as)
         
-        # Generate CRC integer fields for text grouping
+        # Generate hashed integer fields for text grouping
         if with_facet
-          # Postgres probably doesn't handle this
-          column_strings &lt;&lt; &quot;CRC32(#{source_string}) AS #{as}_facet&quot;
+          column_strings &lt;&lt; &quot;#{ADAPTER_SQL_FUNCTIONS[ADAPTER]['hash']}#{source_string}) AS #{as}_facet&quot;
           remaining_columns.delete(&quot;#{as}_facet&quot;)
         end
         [column_strings, remaining_columns]</diff>
      <filename>lib/ultrasphinx/configure.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,6 +6,12 @@ class Array
       set + Array(element)
     end
   end
+  
+  def sum
+    self.inject(0) do |acc, element|
+      acc + element
+    end
+  end
 end
 
 class Object
@@ -66,7 +72,7 @@ class String
     elsif date = Chronic.parse(self)
       date.to_i
     else
-      self
+      raise Ultrasphinx::UsageError, &quot;#{self.inspect} could not be coerced into a numeric value&quot;
     end
   end
 end</diff>
      <filename>lib/ultrasphinx/core_extensions.rb</filename>
    </modified>
    <modified>
      <diff>@@ -205,43 +205,47 @@ Note that your database is never changed by anything Ultrasphinx does.
     
     # Returns the facet map for this query, if facets were used.
     def facets
-      raise UsageError, &quot;No facet field was configured&quot; unless @options['facets']
       run?(true)
+      raise UsageError, &quot;No facet field was configured&quot; unless @options['facets']
       @facets
     end      
           
     # Returns the raw response from the Sphinx client.
     def response
+      run?(true)
       @response
     end
     
     def class_name #:nodoc:
       # Legacy accessor
-      @options['class_name']
+      @options['class_names']
     end
     
     # Returns a hash of total result counts, scoped to each available model. This requires extra queries against the search daemon right now. Set &lt;tt&gt;Ultrasphinx::Search.client_options[:with_subtotals] = true&lt;/tt&gt; to enable the extra queries. Most of the overhead is in instantiating the AR result sets, so the performance hit is not usually significant.
     def subtotals
+      run?(true)
       raise UsageError, &quot;Subtotals are not enabled&quot; unless self.class.client_options['with_subtotals']
       @subtotals
     end
 
     # Returns the total result count.
     def total_entries
+      run?(true)
       [response['total_found'] || 0, MAX_MATCHES].min
     end  
   
     # Returns the response time of the query, in milliseconds.
     def time
+      run?(true)
       response['time']
     end
 
     # Returns whether the query has been run.  
     def run?(should_raise = false)
-      if response.blank? and should_raise
+      if @response.blank? and should_raise
         raise UsageError, &quot;Search has not yet been run&quot; unless run?
       else
-        !response.blank?
+        !@response.blank?
       end
     end
  
@@ -257,6 +261,7 @@ Note that your database is never changed by anything Ultrasphinx does.
         
     # Returns the last available page number in the result set.  
     def page_count
+      run?(true)    
       (total_entries / per_page) + (total_entries % per_page == 0 ? 0 : 1)
     end
             
@@ -327,14 +332,14 @@ Note that your database is never changed by anything Ultrasphinx does.
         # if you don't reify, you'll have to do the modulus reversal yourself to get record ids
         @results = reify_results(@results) if reify
                                 
-      rescue Sphinx::SphinxResponseError, Sphinx::SphinxTemporaryError, Errno::EPIPE =&gt; e
+      rescue Sphinx::SphinxConnectError, Sphinx::SphinxResponseError, Sphinx::SphinxTemporaryError, Errno::ECONNRESET, Errno::EPIPE =&gt; e
         if (tries += 1) &lt;= self.class.client_options['max_retries']
           say &quot;restarting query (#{tries} attempts already) (#{e})&quot;
           sleep(self.class.client_options['retry_sleep_time']) if tries == self.class.client_options['max_retries']
           retry
         else
           say &quot;query failed&quot;
-          raise e
+          raise Sphinx::SphinxConnectError, e.to_s
         end
       end
       </diff>
      <filename>lib/ultrasphinx/search.rb</filename>
    </modified>
    <modified>
      <diff>@@ -21,7 +21,7 @@ module Ultrasphinx
       
         offset, limit = opts['per_page'] * (opts['page'] - 1), opts['per_page']
         
-        request.SetLimits offset, limit, [offset + limit, MAX_MATCHES].min
+        request.SetLimits offset, limit
         request.SetSortMode SPHINX_CLIENT_PARAMS['sort_mode'][opts['sort_mode']], opts['sort_by'].to_s
       
         if weights = opts['weights']
@@ -87,10 +87,14 @@ module Ultrasphinx
         # Set the facet query parameter and modify per-page setting so we snag all the facets
         request.SetGroupBy(facet, Sphinx::Client::SPH_GROUPBY_ATTR, '@count desc')
         limit = self.class.client_options['max_facets']
-        request.SetLimits 0, limit, [limit, MAX_MATCHES].min
+        request.SetLimits 0, limit
         
         # Run the query
-        matches = request.Query(query)['matches']
+        begin
+          matches = request.Query(query)['matches']
+        rescue Sphinx::SphinxInternalError
+          raise ConfigurationError, &quot;Index is out of date. Run 'rake ultrasphinx:index'&quot;
+        end
                 
         # Map the facets back to something sane
         facets = {}
@@ -100,7 +104,7 @@ module Ultrasphinx
           facets[match['@groupby']] = match['@count']
         end
                 
-        # Invert crc's, if we have them
+        # Invert hash's, if we have them
         reverse_map_facets(facets, original_facet)
       end
       
@@ -109,9 +113,9 @@ module Ultrasphinx
       
         if Fields.instance.types[facet] == 'text'        
           # Apply the map, rebuilding if the cache is missing or out-of-date
-          facets = Hash[*(facets.map do |crc, value|
-            rebuild_facet_cache(facet) unless FACET_CACHE[facet] and FACET_CACHE[facet].has_key?(crc)
-            [FACET_CACHE[facet][crc], value]
+          facets = Hash[*(facets.map do |hash, value|
+            rebuild_facet_cache(facet) unless FACET_CACHE[facet] and FACET_CACHE[facet].has_key?(hash)
+            [FACET_CACHE[facet][hash], value]
           end.flatten)]
         end
         
@@ -119,18 +123,21 @@ module Ultrasphinx
       end
       
       def rebuild_facet_cache(facet)
-        # Cache the reverse CRC map for the textual facet if it hasn't been done yet
+        # Cache the reverse hash map for the textual facet if it hasn't been done yet
         # XXX not necessarily optimal since it requires a direct DB hit once per mongrel
-        Ultrasphinx.say &quot;caching CRC reverse map for text facet #{facet}&quot;
+        Ultrasphinx.say &quot;caching hash reverse map for text facet #{facet}&quot;
         
         Fields.instance.classes[facet].each do |klass|
           # you can only use a facet from your own self right now; no includes allowed
-          field = (MODEL_CONFIGURATION[klass.name]['fields'].detect do |field_hash|
+          field = MODEL_CONFIGURATION[klass.name]['fields'].detect do |field_hash|
             field_hash['as'] == facet
-          end)['field']
+          end
+                    
+          raise ConfigurationError, &quot;Model #{klass.name} has the requested '#{facet}' field, but it was not configured for faceting&quot; unless field
+          field = field['field']
       
-          klass.connection.execute(&quot;SELECT #{field} AS value, CRC32(#{field}) AS crc FROM #{klass.table_name} GROUP BY #{field}&quot;).each_hash do |hash|
-            (FACET_CACHE[facet] ||= {})[hash['crc'].to_i] = hash['value']
+          klass.connection.execute(&quot;SELECT #{field} AS value, #{ADAPTER_SQL_FUNCTIONS[ADAPTER]['hash']}#{field}) AS hash FROM #{klass.table_name} GROUP BY #{field}&quot;).each_hash do |hash|
+            (FACET_CACHE[facet] ||= {})[hash['hash'].to_i] = hash['value']
           end                            
         end
         FACET_CACHE[facet]</diff>
      <filename>lib/ultrasphinx/search/internals.rb</filename>
    </modified>
    <modified>
      <diff>@@ -10,13 +10,14 @@ In order to spellcheck your user's query, Ultrasphinx bundles a small spelling m
 
 Make sure Aspell and the Rubygem &lt;tt&gt;raspell&lt;/tt&gt; are installed. See http://blog.evanweaver.com/files/doc/fauna/raspell/ for detailed instructions.
   
-Copy the &lt;tt&gt;examples/app.multi&lt;/tt&gt; file into your Aspell dictionary folder (&lt;tt&gt;/opt/local/share/aspell/&lt;/tt&gt; on Mac, &lt;tt&gt;/usr/lib/aspell-0.60/&lt;/tt&gt; on Linux). This file lets Aspell load a custom wordlist generated by Sphinx from your app data. Modify the file if you don't want to also use the default American English dictionary.
+Copy the &lt;tt&gt;examples/ap.multi&lt;/tt&gt; file into your Aspell dictionary folder (&lt;tt&gt;/opt/local/share/aspell/&lt;/tt&gt; on Mac, &lt;tt&gt;/usr/lib/aspell-0.60/&lt;/tt&gt; on Linux). This file lets Aspell load a custom wordlist generated by Sphinx from your app data (you can configure its filename in the &lt;tt&gt;config/ultrasphinx/*.base&lt;/tt&gt; files). Modify the file if you don't want to also use the default American English dictionary.
   
 Finally, to build the custom wordlist, run:  
   sudo rake ultrasphinx:spelling:build  
 
 You need to use &lt;tt&gt;sudo&lt;/tt&gt; because Ultrasphinx needs to write to the Aspell dictionary folder. Also note that Aspell, &lt;tt&gt;raspell&lt;/tt&gt;, and the custom dictionary must be available on each application server, not on the Sphinx daemon server.
 
+
 == Usage
 
 Now you can see if a query is correctly spelled as so:
@@ -27,7 +28,7 @@ If &lt;tt&gt;@correction&lt;/tt&gt; is not &lt;tt&gt;nil&lt;/tt&gt;, go ahead and suggest it to the user
 =end
 
   module Spell  
-    SP = Aspell.new(&quot;app&quot;)   
+    SP = Aspell.new(Ultrasphinx::DICTIONARY)   
     SP.suggestion_mode = Aspell::NORMAL
     SP.set_option(&quot;ignore-case&quot;, &quot;true&quot;)
     </diff>
      <filename>lib/ultrasphinx/spell.rb</filename>
    </modified>
    <modified>
      <diff>@@ -69,11 +69,13 @@ type = pgsql
   ADAPTER_SQL_FUNCTIONS = {
     'mysql' =&gt; {
       'group_by' =&gt; 'GROUP BY id',
-      'timestamp' =&gt; 'UNIX_TIMESTAMP('
+      'timestamp' =&gt; 'UNIX_TIMESTAMP(',
+      'hash' =&gt; 'CRC32('
     },    
     'postgresql' =&gt; {
       'group_by' =&gt; '',
-      'timestamp' =&gt; 'EXTRACT(EPOCH FROM '
+      'timestamp' =&gt; 'EXTRACT(EPOCH FROM ',
+      'hash' =&gt; 'MD5('
     }      
   }
   
@@ -121,8 +123,11 @@ type = pgsql
   
   # Make sure there's a trailing slash
   INDEX_SETTINGS['path'] = INDEX_SETTINGS['path'].chomp(&quot;/&quot;) + &quot;/&quot; 
+  
+  DICTIONARY = CLIENT_SETTINGS['dictionary_name'] || 'ap'  
+  raise ConfigurationError, &quot;Aspell does not support dictionary names longer than two letters&quot; if DICTIONARY.size &gt; 2
 
-  STOPWORDS_PATH = &quot;#{Ultrasphinx::INDEX_SETTINGS['path']}/stopwords.txt&quot;
+  STOPWORDS_PATH = &quot;#{Ultrasphinx::INDEX_SETTINGS['path']}/#{DICTIONARY}-stopwords.txt&quot;
 
   MODEL_CONFIGURATION = {}     
 </diff>
      <filename>lib/ultrasphinx/ultrasphinx.rb</filename>
    </modified>
    <modified>
      <diff>@@ -83,7 +83,7 @@ namespace :ultrasphinx do
     task :build =&gt; [:_environment] do    
       ENV['OPTS'] = &quot;--buildstops #{Ultrasphinx::STOPWORDS_PATH} #{Ultrasphinx::MAX_WORDS} --buildfreqs&quot;
       Rake::Task[&quot;ultrasphinx:index&quot;].invoke
-      tmpfile = &quot;/tmp/custom_words.txt&quot;
+      tmpfile = &quot;/tmp/ultrasphinx-stopwords.txt&quot;
       words = []
       say &quot;filtering&quot;
       File.open(Ultrasphinx::STOPWORDS_PATH).each do |line|
@@ -96,8 +96,8 @@ namespace :ultrasphinx do
       end
       say &quot;writing #{words.size} words&quot;
       File.open(tmpfile, 'w').write(words.join(&quot;\n&quot;))
-      say &quot;loading into aspell&quot;
-      system(&quot;aspell --lang=en create master custom.rws &lt; #{tmpfile}&quot;)
+      say &quot;loading dictionary '#{Ultrasphinx::DICTIONARY}' into aspell&quot;
+      system(&quot;aspell --lang=en create master #{Ultrasphinx::DICTIONARY}.rws &lt; #{tmpfile}&quot;)
     end
   end
   </diff>
      <filename>tasks/ultrasphinx.rake</filename>
    </modified>
    <modified>
      <diff>@@ -2,5 +2,18 @@ class Seller &lt; ActiveRecord::Base
   belongs_to :user  
   delegate :address, :to =&gt; :user
   
-  is_indexed :fields =&gt; ['company_name', 'created_at', 'capitalization', 'user_id']  
+  is_indexed :fields =&gt; [
+    {:field =&gt; 'company_name', :facet =&gt; true},
+    'created_at', 
+    'capitalization', 
+    'user_id'
+  ]
+  
+  def name 
+    company_name
+  end
+  
+  def metadata
+    &quot;sfdkjl fsdjkl sdfjl fdsjk #{company_name} &quot; * 5
+  end  
 end</diff>
      <filename>test/integration/app/app/models/seller.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,4 +6,6 @@ Rails::Initializer.run do |config|
   config.load_paths &lt;&lt; &quot;#{RAILS_ROOT}/app/models/person&quot; # moduleless model path
 end
 
+Ultrasphinx::Search.client_options['with_subtotals'] = true
+
 # Dependencies.log_activity = true</diff>
      <filename>test/integration/app/config/environment.rb</filename>
    </modified>
    <modified>
      <diff>@@ -28,6 +28,7 @@ searchd
 client
 {
   # Client options
+  dictionary_name = ts
   # How your application connects to the search daemon (not necessarily the same as above)
   server_host = localhost
   server_port = 3313</diff>
      <filename>test/integration/app/config/ultrasphinx/default.base</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
 
-# Auto-generated at Thu Sep 27 04:12:58 -0400 2007.
+# Auto-generated at Wed Oct 03 03:57:12 -0400 2007.
 # Hand modifications will be overwritten.
-# /Users/eweaver/Desktop/projects/fauna/ultrasphinx/trunk/test/integration/app/config/ultrasphinx/default.base
+# /Users/eweaver/Desktop/projects/chow/vendor/plugins/ultrasphinx/test/integration/app/config/ultrasphinx/default.base
 indexer {
   mem_limit = 256M
 }
@@ -18,6 +18,36 @@ searchd {
 
 # Source configuration
 
+source geo__states
+{
+  strip_html = 0
+  sql_range_step = 20000
+  index_html_attrs = 
+  sql_query_post = 
+
+type = mysql
+sql_query_pre = SET SESSION group_concat_max_len = 65535
+sql_query_pre = SET NAMES utf8
+  
+sql_db = app_development
+sql_host = localhost
+sql_pass = 
+sql_user = root
+sql_query_range = SELECT MIN(id), MAX(id) FROM states
+sql_query = SELECT (states.id * 4 + 0) AS id, CAST(GROUP_CONCAT(addresses.name SEPARATOR ' ') AS CHAR) AS address_name, 0 AS capitalization, 'Geo::State' AS class, 0 AS class_id, '' AS company, '' AS company_name, 0 AS company_name_facet, '' AS content, UNIX_TIMESTAMP('1970-01-01 00:00:00') AS created_at, 0 AS deleted, '' AS email, '__empty_searchable__' AS empty_searchable, '' AS login, '' AS name, '' AS state, 0 AS user_id FROM states LEFT OUTER JOIN addresses ON states.id = addresses.state_id WHERE states.id &gt;= $start AND states.id &lt;= $end GROUP BY id
+
+sql_group_column = capitalization
+sql_group_column = class_id
+sql_group_column = company_name_facet
+sql_date_column = created_at
+sql_group_column = deleted
+sql_group_column = user_id
+sql_query_info = SELECT * FROM states WHERE states.id = (($id - 0) / 4)
+}
+
+
+# Source configuration
+
 source sellers
 {
   strip_html = 0
@@ -34,13 +64,45 @@ sql_host = localhost
 sql_pass = 
 sql_user = root
 sql_query_range = SELECT MIN(id), MAX(id) FROM sellers
-sql_query = SELECT (sellers.id * 2 + 0) AS id, sellers.capitalization AS capitalization, 'Seller' AS class, 0 AS class_id, sellers.company_name AS company_name, UNIX_TIMESTAMP(sellers.created_at) AS created_at, '' AS email, '__empty_searchable__' AS empty_searchable, '' AS login, sellers.user_id AS user_id FROM sellers WHERE sellers.id &gt;= $start AND sellers.id &lt;= $end GROUP BY id
+sql_query = SELECT (sellers.id * 4 + 1) AS id, '' AS address_name, sellers.capitalization AS capitalization, 'Seller' AS class, 1 AS class_id, '' AS company, sellers.company_name AS company_name, CRC32(sellers.company_name) AS company_name_facet, '' AS content, UNIX_TIMESTAMP(sellers.created_at) AS created_at, 0 AS deleted, '' AS email, '__empty_searchable__' AS empty_searchable, '' AS login, '' AS name, '' AS state, sellers.user_id AS user_id FROM sellers WHERE sellers.id &gt;= $start AND sellers.id &lt;= $end GROUP BY id
+
+sql_group_column = capitalization
+sql_group_column = class_id
+sql_group_column = company_name_facet
+sql_date_column = created_at
+sql_group_column = deleted
+sql_group_column = user_id
+sql_query_info = SELECT * FROM sellers WHERE sellers.id = (($id - 1) / 4)
+}
+
+
+# Source configuration
+
+source geo__addresses
+{
+  strip_html = 0
+  sql_range_step = 20000
+  index_html_attrs = 
+  sql_query_post = 
+
+type = mysql
+sql_query_pre = SET SESSION group_concat_max_len = 65535
+sql_query_pre = SET NAMES utf8
+  
+sql_db = app_development
+sql_host = localhost
+sql_pass = 
+sql_user = root
+sql_query_range = SELECT MIN(id), MAX(id) FROM addresses
+sql_query = SELECT (addresses.id * 4 + 2) AS id, '' AS address_name, 0 AS capitalization, 'Geo::Address' AS class, 2 AS class_id, '' AS company, '' AS company_name, 0 AS company_name_facet, CONCAT_WS(' ', addresses.line_1, addresses.line_2, addresses.city, addresses.province_region, addresses.zip_postal_code) AS content, UNIX_TIMESTAMP('1970-01-01 00:00:00') AS created_at, 0 AS deleted, '' AS email, '__empty_searchable__' AS empty_searchable, '' AS login, addresses.name AS name, states.name AS state, 0 AS user_id FROM addresses LEFT OUTER JOIN states ON states.id = addresses.state_id WHERE addresses.id &gt;= $start AND addresses.id &lt;= $end GROUP BY id
 
 sql_group_column = capitalization
 sql_group_column = class_id
+sql_group_column = company_name_facet
 sql_date_column = created_at
+sql_group_column = deleted
 sql_group_column = user_id
-sql_query_info = SELECT * FROM sellers WHERE sellers.id = (($id - 0) / 2)
+sql_query_info = SELECT * FROM addresses WHERE addresses.id = (($id - 2) / 4)
 }
 
 
@@ -62,13 +124,15 @@ sql_host = localhost
 sql_pass = 
 sql_user = root
 sql_query_range = SELECT MIN(id), MAX(id) FROM users
-sql_query = SELECT (users.id * 2 + 1) AS id, 0 AS capitalization, 'User' AS class, 1 AS class_id, '' AS company_name, UNIX_TIMESTAMP('1970-01-01 00:00:00') AS created_at, users.email AS email, '__empty_searchable__' AS empty_searchable, users.login AS login, 0 AS user_id FROM users WHERE users.id &gt;= $start AND users.id &lt;= $end GROUP BY id
+sql_query = SELECT (users.id * 4 + 3) AS id, '' AS address_name, 0 AS capitalization, 'User' AS class, 3 AS class_id, sellers.company_name AS company, '' AS company_name, 0 AS company_name_facet, '' AS content, UNIX_TIMESTAMP('1970-01-01 00:00:00') AS created_at, users.deleted AS deleted, users.email AS email, '__empty_searchable__' AS empty_searchable, users.login AS login, '' AS name, '' AS state, 0 AS user_id FROM users LEFT OUTER JOIN sellers ON users.id = sellers.user_id WHERE users.id &gt;= $start AND users.id &lt;= $end AND (deleted = 0) GROUP BY id
 
 sql_group_column = capitalization
 sql_group_column = class_id
+sql_group_column = company_name_facet
 sql_date_column = created_at
+sql_group_column = deleted
 sql_group_column = user_id
-sql_query_info = SELECT * FROM users WHERE users.id = (($id - 1) / 2)
+sql_query_info = SELECT * FROM users WHERE users.id = (($id - 3) / 4)
 }
 
 
@@ -76,6 +140,8 @@ sql_query_info = SELECT * FROM users WHERE users.id = (($id - 1) / 2)
 
 index complete
 {
+  source = geo__addresses
+  source = geo__states
   source = sellers
   source = users
   charset_type = utf-8</diff>
      <filename>test/integration/app/config/ultrasphinx/development.conf.canonical</filename>
    </modified>
    <modified>
      <diff>@@ -4,26 +4,61 @@ require &quot;#{File.dirname(__FILE__)}/../test_helper&quot;
 class SearchTest &lt; Test::Unit::TestCase
 
   S = Ultrasphinx::Search
+  E = Ultrasphinx::UsageError
+  STRFTIME = &quot;%b %d %Y %H:%M:%S&quot; # Chronic can't parse the default date .to_s
 
   def test_simple_query
     assert_nothing_raised do
-      @q = S.new(:query =&gt; 'seller').run
+      @s = S.new(:query =&gt; 'seller').run
     end
-    assert_equal 20, @q.results.size
+    assert_equal 20, @s.results.size
   end  
   
+  def test_query_must_be_run
+    @s = S.new
+    assert_raises(E) { @s.total_entries }
+    assert_raises(E) { @s.response }
+    assert_raises(E) { @s.facets }
+    assert_raises(E) { @s.results }
+  end
+  
+  def test_subtotals
+    @s = S.new.run
+    assert_equal @s.total_entries, @s.subtotals.values.sum
+  end
+  
+  def test_query_retries_and_fails
+    system(&quot;cd #{RAILS_ROOT}; rake ultrasphinx:daemon:stop &amp;&gt; /dev/null&quot;)
+    assert_raises(Sphinx::SphinxConnectError) do
+      S.new.run
+    end
+    system(&quot;cd #{RAILS_ROOT}; rake ultrasphinx:daemon:start &amp;&gt; /dev/null&quot;)
+  end
+  
+  def test_accessors
+    @per_page = 5
+    @page = 3
+    @s = S.new(:query =&gt; 'seller', :per_page =&gt; @per_page, :page =&gt; @page).run
+    assert_equal @per_page, @s.per_page
+    assert_equal @page, @s.page
+    assert_equal @page - 1, @s.previous_page
+    assert_equal @page + 1, @s.next_page
+    assert_equal @per_page * (@page - 1), @s.offset
+    assert @s.page_count &gt;= @s.total_entries / @per_page.to_f
+   end
+  
   def test_empty_query
     @total = Ultrasphinx::MODEL_CONFIGURATION.keys.inject(0) do |acc, class_name| 
       acc + class_name.constantize.count
     end - User.count(:conditions =&gt; {:deleted =&gt; true })
     
     assert_nothing_raised do
-      @q = S.new.run
+      @s = S.new.run
     end
     
     assert_equal(
       @total,
-      @q.total_entries
+      @s.total_entries
     )
   end
   
@@ -48,6 +83,10 @@ class SearchTest &lt; Test::Unit::TestCase
     )
   end
   
+  def test_nil_filter
+  
+  end
+  
   def test_float_range_filter
     @count = Seller.count(:conditions =&gt; 'capitalization &lt;= 29.5 AND capitalization &gt;= 10')
     assert_equal(@count,
@@ -63,6 +102,12 @@ class SearchTest &lt; Test::Unit::TestCase
       S.new(:class_names =&gt; 'Seller', :filters =&gt; {'created_at' =&gt; @first..@last}).run.size)
     assert_equal(@count,
       S.new(:class_names =&gt; 'Seller', :filters =&gt; {'created_at' =&gt; @last..@first}).run.size)
+    assert_equal(@count,
+      S.new(:class_names =&gt; 'Seller', :filters =&gt; {'created_at' =&gt; @last.strftime(STRFTIME)...@first.strftime(STRFTIME)}).run.size)
+
+    assert_raises(Ultrasphinx::UsageError) do
+      S.new(:class_names =&gt; 'Seller', :filters =&gt; {'created_at' =&gt; &quot;bogus&quot;..&quot;sugob&quot;}).run.size
+    end
   end
     
   def test_text_filter
@@ -78,12 +123,51 @@ class SearchTest &lt; Test::Unit::TestCase
     end
   end
   
-  def test_query_filter
+  def test_conditions
+    @deleted_count = User.count(:conditions =&gt; {:deleted =&gt; true })
+    assert_equal 1, @deleted_count
+    assert_equal User.count - @deleted_count, S.new(:class_name =&gt; 'User').run.total_entries 
+  end
+  
+#  def test_mismatched_facet_configuration
+#    assert_raises(Ultrasphinx::ConfigurationError) do 
+#      Ultrasphinx::Search.new(:facets =&gt; 'company_name').run
+#    end
+#  end
+  
+  def test_bogus_facet_name
+    assert_raises(Ultrasphinx::UsageError) do
+      Ultrasphinx::Search.new(:facets =&gt; 'bogus').run
+    end
+  end  
+  
+  def test_text_facet
+    @s = Ultrasphinx::Search.new(:facets =&gt; ['company_name']).run
+    assert_equal 21, @s.facets['company_name'].size
+  end
   
+  def test_numeric_facet
+    @s = Ultrasphinx::Search.new(:facets =&gt; 'user_id').run
+    assert_equal Geo::Address.count + 1, @s.facets['user_id'].size
+    assert @s.facets['user_id'][0] &gt; 1
   end
   
-  def test_weighting
+  def test_multi_facet
+  
+  end
+    
+  def test_weights
+    @unweighted = Ultrasphinx::Search.new(:query =&gt; 'seller1', :per_page =&gt; 1).run.first
+    @weighted = Ultrasphinx::Search.new(:query =&gt; 'seller1', :weights =&gt; {'company' =&gt; 2}, :per_page =&gt; 1).run.first
+    assert_not_equal @unweighted.class, @weighted.class
+  end
   
+  def test_excerpts
+    @s = Ultrasphinx::Search.new(:query =&gt; 'seller10')
+    @excerpted_item = @s.excerpt.first
+    @item = @s.run.first
+    assert_not_equal @item.name, @excerpted_item.name
+    assert_match /strong/, @excerpted_item.name
   end
   
 end
\ No newline at end of file</diff>
      <filename>test/integration/search_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -7,6 +7,9 @@ class SpellTest &lt; Test::Unit::TestCase
     # XXX don't know how to test this sanely
   end
   
-  
+  def test_spelling
+    assert_equal nil, Ultrasphinx::Spell.correct(&quot;correct words&quot;)
+    assert_equal &quot;garbled words&quot;, Ultrasphinx::Spell.correct(&quot;glarbled words&quot;)
+  end  
 
 end
\ No newline at end of file</diff>
      <filename>test/integration/spell_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -3,4 +3,5 @@
 
 Dir.chdir &quot;#{File.dirname(__FILE__)}/integration/app/&quot; do
   system(&quot;rake db:create db:migrate db:fixtures:load us:boot&quot;)
+  system(&quot;sudo rake ultrasphinx:spelling:build&quot;)
 end</diff>
      <filename>test/setup.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,3 +6,9 @@ require 'ruby-debug'
 $LOAD_PATH &lt;&lt; File.dirname(__FILE__)
 
 require 'integration/app/config/environment'
+
+def silently
+  stderr, $stderr = $stderr, StringIO.new
+  yield
+  $stderr = stderr
+end
\ No newline at end of file</diff>
      <filename>test/test_helper.rb</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>examples/app.multi</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>aca1a40ac554ce9d05e0f96849018674bc8a9694</id>
    </parent>
  </parents>
  <author>
    <name>Evan Weaver</name>
    <email>evan@cloudbur.st</email>
  </author>
  <url>http://github.com/fauna/ultrasphinx/commit/3af82ddfbfb5381784a65abb331204a35236f4e6</url>
  <id>3af82ddfbfb5381784a65abb331204a35236f4e6</id>
  <committed-date>2007-10-03T00:58:00-07:00</committed-date>
  <authored-date>2007-10-03T00:58:00-07:00</authored-date>
  <message>90% test coverage; configurable dictionary name; namespaced model fixes; error handling fixes</message>
  <tree>54332b2838aeb1874cb5f8e5f1b35ca59deb2cea</tree>
  <committer>
    <name>Evan Weaver</name>
    <email>evan@cloudbur.st</email>
  </committer>
</commit>
