dm-sphinx-adapter 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/History.txt +12 -0
  2. data/Manifest.txt +24 -13
  3. data/README.txt +44 -28
  4. data/Rakefile +1 -1
  5. data/dm-sphinx-adapter.gemspec +7 -7
  6. data/lib/dm-sphinx-adapter.rb +8 -6
  7. data/lib/dm-sphinx-adapter/adapter.rb +218 -0
  8. data/lib/dm-sphinx-adapter/attribute.rb +38 -0
  9. data/lib/dm-sphinx-adapter/client.rb +109 -0
  10. data/lib/dm-sphinx-adapter/config.rb +122 -0
  11. data/lib/dm-sphinx-adapter/config_parser.rb +71 -0
  12. data/lib/dm-sphinx-adapter/index.rb +38 -0
  13. data/lib/dm-sphinx-adapter/query.rb +67 -0
  14. data/lib/dm-sphinx-adapter/resource.rb +103 -0
  15. data/test/{fixtures/item.sql → files/dm_sphinx_adapter_test.sql} +3 -3
  16. data/test/{fixtures/item_resource_explicit.rb → files/resource_explicit.rb} +5 -6
  17. data/test/{fixtures/item_resource_only.rb → files/resource_resource.rb} +4 -5
  18. data/test/{fixtures/item.rb → files/resource_searchable.rb} +8 -5
  19. data/test/files/resource_storage_name.rb +11 -0
  20. data/test/files/resource_vanilla.rb +7 -0
  21. data/test/{data → files}/sphinx.conf +11 -6
  22. data/test/test_adapter.rb +38 -0
  23. data/test/test_adapter_explicit.rb +48 -0
  24. data/test/test_adapter_resource.rb +25 -0
  25. data/test/test_adapter_searchable.rb +23 -0
  26. data/test/test_adapter_vanilla.rb +46 -0
  27. data/test/test_client.rb +9 -21
  28. data/test/test_config.rb +58 -24
  29. data/test/test_config_parser.rb +29 -0
  30. data/test/test_query.rb +47 -0
  31. data/test/test_type_attribute.rb +8 -0
  32. data/test/test_type_index.rb +8 -0
  33. metadata +38 -19
  34. data/lib/dm-sphinx-adapter/sphinx_adapter.rb +0 -220
  35. data/lib/dm-sphinx-adapter/sphinx_attribute.rb +0 -22
  36. data/lib/dm-sphinx-adapter/sphinx_client.rb +0 -81
  37. data/lib/dm-sphinx-adapter/sphinx_config.rb +0 -160
  38. data/lib/dm-sphinx-adapter/sphinx_index.rb +0 -21
  39. data/lib/dm-sphinx-adapter/sphinx_resource.rb +0 -88
  40. data/test/helper.rb +0 -7
  41. data/test/test_search.rb +0 -52
data/History.txt CHANGED
@@ -1,3 +1,15 @@
1
+ === 0.5 / 2008-12-01
2
+
3
+ * Moved sphinx extended query string generator into a class of its own.
4
+ * Improved generated extended query syntax and added tests.
5
+ * Support for sphinx "" phrase search operator (dm conditions as array).
6
+ * Support for sphinx | OR operator (dm conditions using {:field.in => %w{}}).
7
+
8
+ === 0.4 / 2008-11-21
9
+
10
+ * Fixed broken dm-is-searchable support.
11
+ * Bumped version because the read_one/read_many result structure had to change to support dm-is-searchable.
12
+
1
13
  === 0.3 / 2008-11-18
2
14
 
3
15
  * Removed calls to indexer on create/update. See README.txt
data/Manifest.txt CHANGED
@@ -5,18 +5,29 @@ README.txt
5
5
  Rakefile
6
6
  dm-sphinx-adapter.gemspec
7
7
  lib/dm-sphinx-adapter.rb
8
- lib/dm-sphinx-adapter/sphinx_adapter.rb
9
- lib/dm-sphinx-adapter/sphinx_attribute.rb
10
- lib/dm-sphinx-adapter/sphinx_client.rb
11
- lib/dm-sphinx-adapter/sphinx_config.rb
12
- lib/dm-sphinx-adapter/sphinx_index.rb
13
- lib/dm-sphinx-adapter/sphinx_resource.rb
14
- test/data/sphinx.conf
15
- test/fixtures/item.rb
16
- test/fixtures/item.sql
17
- test/fixtures/item_resource_explicit.rb
18
- test/fixtures/item_resource_only.rb
19
- test/helper.rb
8
+ lib/dm-sphinx-adapter/adapter.rb
9
+ lib/dm-sphinx-adapter/attribute.rb
10
+ lib/dm-sphinx-adapter/client.rb
11
+ lib/dm-sphinx-adapter/config.rb
12
+ lib/dm-sphinx-adapter/config_parser.rb
13
+ lib/dm-sphinx-adapter/index.rb
14
+ lib/dm-sphinx-adapter/query.rb
15
+ lib/dm-sphinx-adapter/resource.rb
16
+ test/files/dm_sphinx_adapter_test.sql
17
+ test/files/resource_explicit.rb
18
+ test/files/resource_resource.rb
19
+ test/files/resource_searchable.rb
20
+ test/files/resource_storage_name.rb
21
+ test/files/resource_vanilla.rb
22
+ test/files/sphinx.conf
23
+ test/test_adapter.rb
24
+ test/test_adapter_explicit.rb
25
+ test/test_adapter_resource.rb
26
+ test/test_adapter_searchable.rb
27
+ test/test_adapter_vanilla.rb
20
28
  test/test_client.rb
21
29
  test/test_config.rb
22
- test/test_search.rb
30
+ test/test_config_parser.rb
31
+ test/test_query.rb
32
+ test/test_type_attribute.rb
33
+ test/test_type_index.rb
data/README.txt CHANGED
@@ -1,23 +1,35 @@
1
1
  = DataMapper Sphinx Adapter
2
2
 
3
- A Sphinx DataMapper adapter.
3
+ * http://dm-sphinx.rubyforge.org
4
+ * http://rubyforge.org/projects/dm-sphinx
5
+ * http://github.com/shanna/dm-sphinx-adapter/tree/master
6
+
7
+ == Description
8
+
9
+ A DataMapper Sphinx adapter.
10
+
11
+ == Dependencies
12
+
13
+ * dm-core ~> 0.9.7
14
+ * riddle ~> 0.9
15
+ * daemon_controller ~> 0.2 (optional)
16
+ * dm-is-searchable ~> 0.9.7 (optional)
17
+
18
+ I'd recommend using the dm-more plugin dm-is-searchable instead of fetching the document id's yourself.
19
+
20
+ == Install
21
+
22
+ * Via git: git clone git://github.com/shanna/iso-country-codes.git
23
+ * Via gem: gem install shanna-dm-sphinx-adapter -s http://gems.github.com
4
24
 
5
25
  == Synopsis
6
26
 
7
27
  DataMapper uses URIs or a connection has to connect to your data-stores. In this case the sphinx search daemon
8
28
  <tt>searchd</tt>.
9
29
 
10
- On its own this adapter will only return an array of document IDs when queried. The dm-more source (not the gem)
30
+ On its own this adapter will only return an array of document hashes when queried. The DataMapper library dm-more
11
31
  however provides dm-is-searchable, a common interface to search one adapter and load documents from another. My
12
- suggestion is to use this adapter in tandem with dm-is-searchable.
13
-
14
- The dm-is-searchable plugin is part of dm-more though unfortunately isn't built and bundled with dm-more gem.
15
- You'll need to checkout the dm-more source with Git from git://github.com/sam/dm-more.git and build/install the
16
- gem yourself.
17
-
18
- git clone git://github.com/sam/dm-more.git
19
- cd dm-more/dm-is-searchable
20
- sudo rake install_gem
32
+ preference is to use this adapter in tandem with dm-is-searchable.
21
33
 
22
34
  Like all DataMapper adapters you can connect with a Hash or URI.
23
35
 
@@ -59,7 +71,19 @@ Alternatively supply a Hash:
59
71
  ids = docs.map{|doc| doc[:id]}
60
72
  items = Item.all(:id => ids) # Search :default for all the document id's returned by sphinx.
61
73
 
62
- === DataMapper and Is Searchable
74
+ === DataMapper and IsSearchable
75
+
76
+ IsSearchable is a DataMapper plugin that provides a common search interface when searching from one adapter and reading
77
+ documents from another.
78
+
79
+ IsSearchable will read resources from your +:default+ repository on behalf of a search adapter such as
80
+ +dm-sphinx-adapter+ and +dm-ferret-adapter+. This saves some of the grunt work (as shown in the previous example) by
81
+ mapping the resulting document id's from a search with your +:search+ adapter into a suitable #first or #all query for
82
+ your +:default+ repository.
83
+
84
+ IsSearchable adds a single class method to your resource. The first argument is a +Hash+ of DataMapper::Query
85
+ conditions to pass to your search adapter (in this case +dm-sphinx-adapter+). An optional second Hash of
86
+ DataMapper::Query conditions can also be passed and will be appended to the query on your +:default+ database.
63
87
 
64
88
  require 'rubygems'
65
89
  require 'dm-core'
@@ -82,7 +106,7 @@ Alternatively supply a Hash:
82
106
  # Fire up your sphinx search daemon and start searching.
83
107
  items = Item.search(:name => 'barney') # Search 'items' index for '@name barney'
84
108
 
85
- === Merb, DataMapper and Is Searchable
109
+ === Merb, DataMapper and IsSearchable
86
110
 
87
111
  # config/init.rb
88
112
  dependency 'dm-is-searchable'
@@ -110,7 +134,7 @@ Alternatively supply a Hash:
110
134
  # Fire up your sphinx search daemon and start searching.
111
135
  Item.search(:name => 'barney') # Search 'items' index for '@name barney'
112
136
 
113
- === DataMapper::SphinxResource
137
+ === DataMapper, IsSearchable and DataMapper::SphinxResource
114
138
 
115
139
  For finer grained control you can include DataMapper::SphinxResource. For instance you can search one or more indexes
116
140
  and sort, include or exclude by attributes defined in your sphinx configuration:
@@ -135,7 +159,7 @@ and sort, include or exclude by attributes defined in your sphinx configuration:
135
159
  # Search 'items, items_delta' index for '@name barney' updated in the last 30 minutes.
136
160
  Item.search(:name => 'barney', :updated => (Time.now - 1800 .. Time.now))
137
161
 
138
- == Sphinx Configuration.
162
+ == Sphinx Configuration
139
163
 
140
164
  Though you don't have to supply the sphinx configuration file to dm-sphinx-adapter I'd recommend doing it anyway.
141
165
  It's more DRY since all searchd/indexer options can be read straight from the configuration.
@@ -155,7 +179,7 @@ or whatever in production. Use the Hash form of DataMapper#setup and supply the
155
179
  daemon_controller will start searchd on demand.
156
180
 
157
181
  It is already strongly encouraged but you will need to specify the path to your sphinx configuration file in order for
158
- searchd to run. See Sphinx Configuration, DataMapper::SphinxManagedClient.
182
+ searchd to run. See Sphinx Configuration, DataMapper::Adapters::Sphinx::ManagedClient.
159
183
 
160
184
  The daemon_controller library can be found only on github, not rubyforge.
161
185
  See http://github.com/FooBarWidget/daemon_controller/tree/master
@@ -173,20 +197,12 @@ an endless loop, with a few seconds of sleep in between to allow searchd some he
173
197
 
174
198
  == Todo
175
199
 
176
- * Tests. Clearly I only test what I see as important or broken which drives TDD people crazy sometimes :)
177
200
  * Loads of documentation. Most of it is unchecked YARD at the moment.
178
- * Add DataMapper::SphinxClient#attribute_set to allow attribute modification on one or more indexes. It's the only
179
- thing missing if you understand the pitfalls and still want to add thinking-sphinx like delta indexing to your
180
- resource.
181
-
182
- == Dependencies
183
-
184
- dm-core and riddle are technically the only requirements though I'd recommend using the dm-more plugin dm-is-searchable
185
- instead of fetching the document id's yourself.
186
-
187
- Unfortunately dm-is-searchable isn't installed even when you build the dm-more gem from github master. You'll need to
188
- build and install the gem yourself from source.
201
+ * Add DataMapper::Adapters::Sphinx::Client#attribute_set to allow attribute modification on one or more indexes. It's
202
+ the only thing missing if you understand the pitfalls and still want to add thinking-sphinx like delta indexing to
203
+ your resource.
189
204
 
190
205
  == Contributing
191
206
 
192
207
  Go nuts. Just send me a pull request (github or otherwise) when you are happy with your code.
208
+
data/Rakefile CHANGED
@@ -3,7 +3,7 @@
3
3
  require 'rubygems'
4
4
  require 'hoe'
5
5
 
6
- Hoe.new('dm-sphinx-adapter', '0.4') do |p|
6
+ Hoe.new('dm-sphinx-adapter', '0.5') do |p|
7
7
  p.developer('Shane Hanna', 'shane.hanna@gmail.com')
8
8
  p.extra_deps = [
9
9
  ['dm-core', '~> 0.9.7'],
@@ -2,23 +2,23 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{dm-sphinx-adapter}
5
- s.version = "0.4"
5
+ s.version = "0.5"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Shane Hanna"]
9
- s.date = %q{2008-11-20}
10
- s.description = %q{}
9
+ s.date = %q{2008-12-01}
10
+ s.description = %q{A DataMapper Sphinx adapter.}
11
11
  s.email = ["shane.hanna@gmail.com"]
12
12
  s.extra_rdoc_files = ["History.txt", "LICENCE.txt", "Manifest.txt", "README.txt"]
13
- s.files = ["History.txt", "LICENCE.txt", "Manifest.txt", "README.txt", "Rakefile", "dm-sphinx-adapter.gemspec", "lib/dm-sphinx-adapter.rb", "lib/dm-sphinx-adapter/sphinx_adapter.rb", "lib/dm-sphinx-adapter/sphinx_attribute.rb", "lib/dm-sphinx-adapter/sphinx_client.rb", "lib/dm-sphinx-adapter/sphinx_config.rb", "lib/dm-sphinx-adapter/sphinx_index.rb", "lib/dm-sphinx-adapter/sphinx_resource.rb", "test/data/sphinx.conf", "test/fixtures/item.rb", "test/fixtures/item.sql", "test/fixtures/item_resource_explicit.rb", "test/fixtures/item_resource_only.rb", "test/helper.rb", "test/test_client.rb", "test/test_config.rb", "test/test_search.rb"]
13
+ s.files = ["History.txt", "LICENCE.txt", "Manifest.txt", "README.txt", "Rakefile", "dm-sphinx-adapter.gemspec", "lib/dm-sphinx-adapter.rb", "lib/dm-sphinx-adapter/adapter.rb", "lib/dm-sphinx-adapter/attribute.rb", "lib/dm-sphinx-adapter/client.rb", "lib/dm-sphinx-adapter/config.rb", "lib/dm-sphinx-adapter/config_parser.rb", "lib/dm-sphinx-adapter/index.rb", "lib/dm-sphinx-adapter/query.rb", "lib/dm-sphinx-adapter/resource.rb", "test/files/dm_sphinx_adapter_test.sql", "test/files/resource_explicit.rb", "test/files/resource_resource.rb", "test/files/resource_searchable.rb", "test/files/resource_storage_name.rb", "test/files/resource_vanilla.rb", "test/files/sphinx.conf", "test/test_adapter.rb", "test/test_adapter_explicit.rb", "test/test_adapter_resource.rb", "test/test_adapter_searchable.rb", "test/test_adapter_vanilla.rb", "test/test_client.rb", "test/test_config.rb", "test/test_config_parser.rb", "test/test_query.rb", "test/test_type_attribute.rb", "test/test_type_index.rb"]
14
14
  s.has_rdoc = true
15
- s.homepage = %q{A Sphinx DataMapper adapter.}
15
+ s.homepage = %q{http://rubyforge.org/projects/dm-sphinx/}
16
16
  s.rdoc_options = ["--main", "README.txt"]
17
17
  s.require_paths = ["lib"]
18
18
  s.rubyforge_project = %q{dm-sphinx-adapter}
19
19
  s.rubygems_version = %q{1.3.0}
20
- s.summary = %q{}
21
- s.test_files = ["test/test_client.rb", "test/test_config.rb", "test/test_search.rb"]
20
+ s.summary = %q{A DataMapper Sphinx adapter.}
21
+ s.test_files = ["test/test_adapter.rb", "test/test_adapter_explicit.rb", "test/test_adapter_resource.rb", "test/test_adapter_searchable.rb", "test/test_adapter_vanilla.rb", "test/test_client.rb", "test/test_config.rb", "test/test_config_parser.rb", "test/test_query.rb", "test/test_type_attribute.rb", "test/test_type_index.rb"]
22
22
 
23
23
  if s.respond_to? :specification_version then
24
24
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
@@ -8,10 +8,12 @@ require 'dm-core'
8
8
  # TODO: I think I might move everything to DataMapper::Sphinx::* and ignore the default naming convention.
9
9
  require 'pathname'
10
10
  dir = Pathname(__FILE__).dirname.expand_path / 'dm-sphinx-adapter'
11
- require dir / 'sphinx_config'
12
- require dir / 'sphinx_client'
13
- require dir / 'sphinx_adapter'
14
- require dir / 'sphinx_index'
15
- require dir / 'sphinx_attribute'
16
- require dir / 'sphinx_resource'
11
+ require dir / 'config'
12
+ require dir / 'config_parser'
13
+ require dir / 'client'
14
+ require dir / 'query'
15
+ require dir / 'adapter'
16
+ require dir / 'index'
17
+ require dir / 'attribute'
18
+ require dir / 'resource'
17
19
 
@@ -0,0 +1,218 @@
1
+ require 'benchmark'
2
+
3
+ module DataMapper
4
+ module Adapters
5
+ module Sphinx
6
+ # == Synopsis
7
+ #
8
+ # DataMapper uses URIs or a connection has to connect to your data-stores. In this case the sphinx search daemon
9
+ # <tt>searchd</tt>.
10
+ #
11
+ # On its own this adapter will only return an array of document hashes when queried. The DataMapper library dm-more
12
+ # however provides dm-is-searchable, a common interface to search one adapter and load documents from another. My
13
+ # preference is to use this adapter in tandem with dm-is-searchable.
14
+ #
15
+ # Like all DataMapper adapters you can connect with a Hash or URI.
16
+ #
17
+ # A URI:
18
+ # DataMapper.setup(:search, 'sphinx://localhost')
19
+ #
20
+ # The breakdown is:
21
+ # "#{adapter}://#{host}:#{port}/#{config}"
22
+ # - adapter Must be :sphinx
23
+ # - host Hostname (default: localhost)
24
+ # - port Optional port number (default: 3312)
25
+ # - config Optional but recommended path to sphinx config file.
26
+ #
27
+ # Alternatively supply a Hash:
28
+ # DataMapper.setup(:search, {
29
+ # :adapter => 'sphinx', # required
30
+ # :config => './sphinx.conf' # optional. Recommended though.
31
+ # :host => 'localhost', # optional. Default: localhost
32
+ # :port => 3312 # optional. Default: 3312
33
+ # :managed => true # optional. Self managed searchd server using daemon_controller.
34
+ # })
35
+ class Adapter < AbstractAdapter
36
+
37
+ # ==== See
38
+ # * DataMapper::Adapters::Sphinx::Config
39
+ # * DataMapper::Adapters::Sphinx::Client
40
+ #
41
+ # ==== Parameters
42
+ # uri_or_options<URI, DataObject::URI, Addressable::URI, String, Hash, Pathname>::
43
+ # DataMapper uri or options hash.
44
+ def initialize(name, uri_or_options)
45
+ super
46
+
47
+ managed = !!(uri_or_options.kind_of?(Hash) && uri_or_options[:managed])
48
+ @client = managed ? ManagedClient.new(uri_or_options) : Client.new(uri_or_options)
49
+ end
50
+
51
+ # Interaction with searchd and indexer.
52
+ #
53
+ # ==== See
54
+ # * DataMapper::Adapters::Sphinx::Client
55
+ # * DataMapper::Adapters::Sphinx::ManagedClient
56
+ #
57
+ # ==== Returns
58
+ # DataMapper::Adapters::Sphinx::Client:: The client.
59
+ attr_reader :client
60
+
61
+ def create(resources) #:nodoc:
62
+ true
63
+ end
64
+
65
+ def delete(query) #:nodoc:
66
+ true
67
+ end
68
+
69
+ # Query your Sphinx repository and return all matching documents.
70
+ #
71
+ # ==== Notes
72
+ #
73
+ # These methods are public but normally called indirectly through DataMapper::Resource#get,
74
+ # DataMapper::Resource#first or DataMapper::Resource#all.
75
+ #
76
+ # ==== Parameters
77
+ # query<DataMapper::Query>:: The query object.
78
+ #
79
+ # ==== Returns
80
+ # Array<Hash>:: An array of document hashes. <tt>[{:id => 1}, {:id => 2}]</tt>
81
+ # Array<>:: An empty array if no documents match.
82
+ def read_many(query)
83
+ read(query)
84
+ end
85
+
86
+ # Query your Sphinx repository and return the first document matched.
87
+ #
88
+ # ==== Notes
89
+ #
90
+ # These methods are public but normally called indirectly through DataMapper::Resource#get,
91
+ # DataMapper::Resource#first or DataMapper::Resource#all.
92
+ #
93
+ # ==== Parameters
94
+ # query<DataMapper::Query>:: The query object.
95
+ #
96
+ # ==== Returns
97
+ # Hash:: An document hash of the first document matched. <tt>{:id => 1}</tt>
98
+ # Nil:: If no documents match.
99
+ def read_one(query)
100
+ read(query).first
101
+ end
102
+
103
+ protected
104
+ # List sphinx indexes to search.
105
+ #
106
+ # If no indexes are explicitly declared using DataMapper::Adapters::Sphinx::Resource then the default storage
107
+ # name is used.
108
+ #
109
+ # ==== See
110
+ # * DataMapper::Adapters::Sphinx::Resource::ClassMethods#sphinx_indexes
111
+ #
112
+ # ==== Parameters
113
+ # model<DataMapper::Model>:: The DataMapper::Model.
114
+ #
115
+ # ==== Returns
116
+ # Array<DataMapper::Adapters::Sphinx::Index>:: Index objects from the model.
117
+ def indexes(model)
118
+ indexes = model.sphinx_indexes(repository(self.name).name) if model.respond_to?(:sphinx_indexes)
119
+ if indexes.nil? or indexes.empty?
120
+ indexes = [Index.new(model, model.storage_name)]
121
+ end
122
+ indexes
123
+ end
124
+
125
+ # List sphinx delta indexes to search.
126
+ #
127
+ # ==== See
128
+ # * DataMapper::Adapters::Sphinx::Resource::ClassMethods#sphinx_indexes
129
+ #
130
+ # ==== Parameters
131
+ # model<DataMapper::Model>:: The DataMapper::Model.
132
+ #
133
+ # ==== Returns
134
+ # Array<DataMapper::Adapters::Sphinx::Index>:: Index objects from the model.
135
+ def delta_indexes(model)
136
+ indexes(model).find_all{|i| i.delta?}
137
+ end
138
+
139
+ # Query sphinx for a list of document IDs.
140
+ #
141
+ # ==== Parameters
142
+ # query<DataMapper::Query>:: The query object.
143
+ #
144
+ # ==== Returns
145
+ # Array<Hash>:: An array of document hashes. <tt>[{:id => 1}, {:id => 2}]</tt>
146
+ # Array<>:: An empty array if no documents match.
147
+ def read(query)
148
+ from = indexes(query.model).map{|index| index.name}.join(', ')
149
+ search = Sphinx::Query.new(query).to_s
150
+ options = {
151
+ :match_mode => :extended,
152
+ :filters => search_filters(query) # By attribute.
153
+ }
154
+ options[:limit] = query.limit.to_i if query.limit
155
+ options[:offset] = query.offset.to_i if query.offset
156
+
157
+ if order = search_order(query)
158
+ options.update(
159
+ :sort_mode => :extended,
160
+ :sort_by => order
161
+ )
162
+ end
163
+
164
+ res = @client.search(search, from, options)
165
+ raise res[:error] unless res[:error].nil?
166
+
167
+ DataMapper.logger.info(
168
+ %q{Sphinx (%.3f): search '%s' in '%s' found %d documents} % [res[:time], search, from, res[:total]]
169
+ )
170
+ res[:matches].map{|doc| {:id => doc[:doc]}}
171
+ end
172
+
173
+
174
+ # Riddle search filters for attributes.
175
+ def search_filters(query) #:nodoc:
176
+ filters = []
177
+ query.conditions.each do |operator, attribute, value|
178
+ next unless attribute.kind_of? Sphinx::Attribute
179
+ filters << case operator
180
+ when :eql, :like then Riddle::Client::Filter.new(attribute.name.to_s, filter_value(value))
181
+ when :not then Riddle::Client::Filter.new(attribute.name.to_s, filter_value(value), true)
182
+ else raise NotImplementedError.new("Sphinx: Query attributes do not support the #{operator} operator")
183
+ end
184
+ end
185
+ filters
186
+ end
187
+
188
+ # TODO: How do you tell the difference between the default query order and someone explicitly asking for
189
+ # sorting by the primary key? I don't think you can at the moment.
190
+ def search_order(query) #:nodoc:
191
+ by = []
192
+ query.order.each do |order|
193
+ next unless order.property.kind_of? Sphinx::Attribute
194
+ by << [order.property.field, order.direction].join(' ')
195
+ end
196
+ by.empty? ? nil : by.join(', ')
197
+ end
198
+
199
+ # TODO: Move this to Attribute#dump.
200
+ # This is ninja'd straight from TS just to get things going.
201
+ def filter_value(value) #:nodoc:
202
+ case value
203
+ when Range
204
+ value.first.is_a?(Time) ? value.first.to_i..value.last.to_i : value
205
+ when Array
206
+ value.collect { |val| val.is_a?(Time) ? val.to_i : val }
207
+ else
208
+ Array(value)
209
+ end
210
+ end
211
+ end # Adapter
212
+ end # Sphinx
213
+
214
+ # Keep magic in DataMapper#setup happy.
215
+ SphinxAdapter = Sphinx::Adapter
216
+ end # Adapters
217
+ end # DataMapper
218
+