dm-sphinx-adapter 0.5 → 0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. data/History.txt +5 -0
  2. data/Manifest.txt +12 -19
  3. data/README.txt +20 -41
  4. data/Rakefile +2 -3
  5. data/dm-sphinx-adapter.gemspec +6 -9
  6. data/lib/dm-sphinx-adapter.rb +14 -11
  7. data/lib/dm-sphinx-adapter/adapter.rb +36 -62
  8. data/lib/dm-sphinx-adapter/attribute.rb +48 -3
  9. data/lib/riddle.rb +28 -0
  10. data/lib/riddle/client.rb +619 -0
  11. data/lib/riddle/client/filter.rb +53 -0
  12. data/lib/riddle/client/message.rb +65 -0
  13. data/lib/riddle/client/response.rb +84 -0
  14. data/test/files/model.rb +23 -0
  15. data/test/files/mysql5.sphinx.conf +97 -0
  16. data/test/files/mysql5.sql +26 -0
  17. data/test/helper.rb +51 -0
  18. data/test/test_adapter.rb +74 -28
  19. data/test/test_attribute.rb +36 -0
  20. data/test/test_index.rb +30 -0
  21. data/test/test_query.rb +47 -32
  22. data/test/test_resource.rb +17 -0
  23. metadata +18 -41
  24. data/lib/dm-sphinx-adapter/client.rb +0 -109
  25. data/lib/dm-sphinx-adapter/config.rb +0 -122
  26. data/lib/dm-sphinx-adapter/config_parser.rb +0 -71
  27. data/test/files/dm_sphinx_adapter_test.sql +0 -21
  28. data/test/files/resource_explicit.rb +0 -25
  29. data/test/files/resource_resource.rb +0 -19
  30. data/test/files/resource_searchable.rb +0 -16
  31. data/test/files/resource_storage_name.rb +0 -11
  32. data/test/files/resource_vanilla.rb +0 -7
  33. data/test/files/sphinx.conf +0 -78
  34. data/test/test_adapter_explicit.rb +0 -48
  35. data/test/test_adapter_resource.rb +0 -25
  36. data/test/test_adapter_searchable.rb +0 -23
  37. data/test/test_adapter_vanilla.rb +0 -46
  38. data/test/test_client.rb +0 -31
  39. data/test/test_config.rb +0 -75
  40. data/test/test_config_parser.rb +0 -29
  41. data/test/test_type_attribute.rb +0 -8
  42. data/test/test_type_index.rb +0 -8
data/History.txt CHANGED
@@ -1,3 +1,8 @@
1
+ === 0.6 / 2008-12-13
2
+
3
+ * Removed managed client and all related libs.
4
+ * Switched to Shoulda for tests in an effort to clean them up a bit.
5
+
1
6
  === 0.5 / 2008-12-01
2
7
 
3
8
  * Moved sphinx extended query string generator into a class of its own.
data/Manifest.txt CHANGED
@@ -7,27 +7,20 @@ dm-sphinx-adapter.gemspec
7
7
  lib/dm-sphinx-adapter.rb
8
8
  lib/dm-sphinx-adapter/adapter.rb
9
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
10
  lib/dm-sphinx-adapter/index.rb
14
11
  lib/dm-sphinx-adapter/query.rb
15
12
  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
13
+ lib/riddle.rb
14
+ lib/riddle/client.rb
15
+ lib/riddle/client/filter.rb
16
+ lib/riddle/client/message.rb
17
+ lib/riddle/client/response.rb
18
+ test/files/model.rb
19
+ test/files/mysql5.sphinx.conf
20
+ test/files/mysql5.sql
21
+ test/helper.rb
23
22
  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
28
- test/test_client.rb
29
- test/test_config.rb
30
- test/test_config_parser.rb
23
+ test/test_attribute.rb
24
+ test/test_index.rb
31
25
  test/test_query.rb
32
- test/test_type_attribute.rb
33
- test/test_type_index.rb
26
+ test/test_resource.rb
data/README.txt CHANGED
@@ -11,15 +11,13 @@ A DataMapper Sphinx adapter.
11
11
  == Dependencies
12
12
 
13
13
  * dm-core ~> 0.9.7
14
- * riddle ~> 0.9
15
- * daemon_controller ~> 0.2 (optional)
16
14
  * dm-is-searchable ~> 0.9.7 (optional)
17
15
 
18
16
  I'd recommend using the dm-more plugin dm-is-searchable instead of fetching the document id's yourself.
19
17
 
20
18
  == Install
21
19
 
22
- * Via git: git clone git://github.com/shanna/iso-country-codes.git
20
+ * Via git: git clone git://github.com/shanna/dm-sphinx-adapter.git
23
21
  * Via gem: gem install shanna-dm-sphinx-adapter -s http://gems.github.com
24
22
 
25
23
  == Synopsis
@@ -27,9 +25,10 @@ I'd recommend using the dm-more plugin dm-is-searchable instead of fetching the
27
25
  DataMapper uses URIs or a connection has to connect to your data-stores. In this case the sphinx search daemon
28
26
  <tt>searchd</tt>.
29
27
 
30
- On its own this adapter will only return an array of document hashes when queried. The DataMapper library dm-more
31
- however provides dm-is-searchable, a common interface to search one adapter and load documents from another. My
32
- preference is to use this adapter in tandem with dm-is-searchable.
28
+ On its own this adapter will only return an array of document hashes when queried. The DataMapper library
29
+ <tt>dm-is-searchable</tt> however provides a common interface to search one adapter and load documents from another. My
30
+ preference is to use this adapter in tandem with <tt>dm-is-searchable</tt>. See further examples in the synopsis for
31
+ usage with <tt>dm-is-searchable</tt>.
33
32
 
34
33
  Like all DataMapper adapters you can connect with a Hash or URI.
35
34
 
@@ -41,7 +40,6 @@ The breakdown is:
41
40
  - adapter Must be :sphinx
42
41
  - host Hostname (default: localhost)
43
42
  - port Optional port number (default: 3312)
44
- - config Optional but strongly recommended path to sphinx config file.
45
43
 
46
44
  Alternatively supply a Hash:
47
45
  DataMapper.setup(:search, {
@@ -49,7 +47,6 @@ Alternatively supply a Hash:
49
47
  :config => './sphinx.conf' # optional. Recommended though.
50
48
  :host => 'localhost', # optional. Default: localhost
51
49
  :port => 3312 # optional. Default: 3312
52
- :managed => true # optional. Self managed searchd server using daemon_controller.
53
50
  }
54
51
 
55
52
  === DataMapper
@@ -76,14 +73,16 @@ Alternatively supply a Hash:
76
73
  IsSearchable is a DataMapper plugin that provides a common search interface when searching from one adapter and reading
77
74
  documents from another.
78
75
 
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.
76
+ IsSearchable will read resources from your <tt>:default</tt> repository on behalf of a search adapter such as
77
+ <tt>dm-sphinx-adapter</tt> and <tt>dm-ferret-adapter</tt>. This saves some of the grunt work (as shown in the previous
78
+ example) by mapping the resulting document id's from a search with your <tt>:search</tt> adapter into a suitable
79
+ <tt>#first</tt> or <tt>#all</tt> query for your <tt>:default</tt> repository.
83
80
 
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.
81
+ IsSearchable adds a single class method to your resource. The first argument is a <tt>Hash</tt> of
82
+ <tt>DataMapper::Query</tt> conditions to pass to your search adapter (in this case <tt>dm-sphinx-adapter</tt>). An
83
+ optional second <tt>Hash</tt> of <tt>DataMapper::Query</tt> conditions can also be passed and will be appended to the
84
+ query on your <tt>:default</tt> database. This can be handy if you need to add extra exclusions that aren't possible
85
+ using <tt>dm-sphinx-adapter</tt> such as <tt>#gt</tt> or <tt>#lt</tt> conditions.
87
86
 
88
87
  require 'rubygems'
89
88
  require 'dm-core'
@@ -140,7 +139,6 @@ For finer grained control you can include DataMapper::SphinxResource. For instan
140
139
  and sort, include or exclude by attributes defined in your sphinx configuration:
141
140
 
142
141
  class Item
143
- include DataMapper::Resource # Optional, included by SphinxResource if you leave it out yourself.
144
142
  include DataMapper::SphinxResource
145
143
  property :id, Serial
146
144
  property :name, String
@@ -161,28 +159,16 @@ and sort, include or exclude by attributes defined in your sphinx configuration:
161
159
 
162
160
  == Sphinx Configuration
163
161
 
164
- Though you don't have to supply the sphinx configuration file to dm-sphinx-adapter I'd recommend doing it anyway.
165
- It's more DRY since all searchd/indexer options can be read straight from the configuration.
166
-
167
- DataMapper.setup(:search, :adapter => 'sphinx', :config => '/path/to/sphinx.conf')
168
- DataMapper.setup(:search, 'sphinx://localhost/path/to/sphinx.conf')
169
-
170
- If your sphinx.conf lives in either of the default locations /usr/local/etc/sphinx.conf or ./sphinx.conf then you
171
- only need to supply:
172
-
173
- DataMapper.setup(:search, :adapter => 'sphinx')
162
+ No limitations, restrictions or requirement are imposed on your sphinx configuration. The adapter will not generate nor
163
+ overwrite your finely crafted config file.
174
164
 
175
165
  == Searchd
176
166
 
177
- As of 0.2 I've added a managed searchd option using daemon_controller. It may come in handy if you only use God, Monit
178
- or whatever in production. Use the Hash form of DataMapper#setup and supply the option :managed with a true value and
179
- daemon_controller will start searchd on demand.
167
+ To keep things simple, this adapter does not manage your sphinx server. Try one of these fine offerings:
180
168
 
181
- It is already strongly encouraged but you will need to specify the path to your sphinx configuration file in order for
182
- searchd to run. See Sphinx Configuration, DataMapper::Adapters::Sphinx::ManagedClient.
183
-
184
- The daemon_controller library can be found only on github, not rubyforge.
185
- See http://github.com/FooBarWidget/daemon_controller/tree/master
169
+ * god[http://god.rubyforge.org]
170
+ * daemon_controller[http://github.com/FooBarWidget/daemon_controller/tree/master]
171
+ * monit[http://www.tildeslash.com/monit]
186
172
 
187
173
  == Indexer and Live(ish) updates.
188
174
 
@@ -195,13 +181,6 @@ For reliable live(ish) updates in a main + delta scheme it's probably best you s
195
181
  Andrew (Shodan) Aksyonoff of Sphinx suggests a cronjob or alternatively if you need even less lag to "run indexer in
196
182
  an endless loop, with a few seconds of sleep in between to allow searchd some headroom to pick up the changes".
197
183
 
198
- == Todo
199
-
200
- * Loads of documentation. Most of it is unchecked YARD at the moment.
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.
204
-
205
184
  == Contributing
206
185
 
207
186
  Go nuts. Just send me a pull request (github or otherwise) when you are happy with your code.
data/Rakefile CHANGED
@@ -3,11 +3,10 @@
3
3
  require 'rubygems'
4
4
  require 'hoe'
5
5
 
6
- Hoe.new('dm-sphinx-adapter', '0.5') do |p|
6
+ Hoe.new('dm-sphinx-adapter', '0.6') do |p|
7
7
  p.developer('Shane Hanna', 'shane.hanna@gmail.com')
8
8
  p.extra_deps = [
9
- ['dm-core', '~> 0.9.7'],
10
- ['riddle', '~> 0.9']
9
+ ['dm-core', '~> 0.9.7']
11
10
  ]
12
11
  end
13
12
 
@@ -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.5"
5
+ s.version = "0.6"
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-12-01}
9
+ s.date = %q{2008-12-13}
10
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/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"]
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/index.rb", "lib/dm-sphinx-adapter/query.rb", "lib/dm-sphinx-adapter/resource.rb", "lib/riddle.rb", "lib/riddle/client.rb", "lib/riddle/client/filter.rb", "lib/riddle/client/message.rb", "lib/riddle/client/response.rb", "test/files/model.rb", "test/files/mysql5.sphinx.conf", "test/files/mysql5.sql", "test/helper.rb", "test/test_adapter.rb", "test/test_attribute.rb", "test/test_index.rb", "test/test_query.rb", "test/test_resource.rb"]
14
14
  s.has_rdoc = true
15
- s.homepage = %q{http://rubyforge.org/projects/dm-sphinx/}
15
+ s.homepage = %q{http://dm-sphinx.rubyforge.org}
16
16
  s.rdoc_options = ["--main", "README.txt"]
17
17
  s.require_paths = ["lib"]
18
18
  s.rubyforge_project = %q{dm-sphinx-adapter}
19
- s.rubygems_version = %q{1.3.0}
19
+ s.rubygems_version = %q{1.3.1}
20
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"]
21
+ s.test_files = ["test/test_adapter.rb", "test/test_attribute.rb", "test/test_index.rb", "test/test_query.rb", "test/test_resource.rb"]
22
22
 
23
23
  if s.respond_to? :specification_version then
24
24
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
@@ -26,16 +26,13 @@ Gem::Specification.new do |s|
26
26
 
27
27
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
28
  s.add_runtime_dependency(%q<dm-core>, ["~> 0.9.7"])
29
- s.add_runtime_dependency(%q<riddle>, ["~> 0.9"])
30
29
  s.add_development_dependency(%q<hoe>, [">= 1.8.2"])
31
30
  else
32
31
  s.add_dependency(%q<dm-core>, ["~> 0.9.7"])
33
- s.add_dependency(%q<riddle>, ["~> 0.9"])
34
32
  s.add_dependency(%q<hoe>, [">= 1.8.2"])
35
33
  end
36
34
  else
37
35
  s.add_dependency(%q<dm-core>, ["~> 0.9.7"])
38
- s.add_dependency(%q<riddle>, ["~> 0.9"])
39
36
  s.add_dependency(%q<hoe>, [">= 1.8.2"])
40
37
  end
41
38
  end
@@ -1,19 +1,22 @@
1
1
  require 'rubygems'
2
2
 
3
3
  # TODO: Hide the shitload of dm-core warnings or at least try to?
4
- $VERBOSE = nil
5
- gem 'dm-core', '~> 0.9.7'
6
- require 'dm-core'
4
+ old_verbose, $VERBOSE = $VERBOSE, nil
5
+ gem 'dm-core', '~> 0.9.7'
6
+ require 'dm-core'
7
+ $VERBOSE = old_verbose
7
8
 
8
- # TODO: I think I might move everything to DataMapper::Sphinx::* and ignore the default naming convention.
9
9
  require 'pathname'
10
- dir = Pathname(__FILE__).dirname.expand_path / 'dm-sphinx-adapter'
11
- require dir / 'config'
12
- require dir / 'config_parser'
13
- require dir / 'client'
14
- require dir / 'query'
10
+ lib = Pathname(__FILE__).dirname.expand_path
11
+ dir = lib / 'dm-sphinx-adapter'
12
+
13
+ # Bundled Riddle since the gem is very old and we don't need any of the config generation stuff.
14
+ $:.unshift lib
15
+ require 'riddle'
16
+
17
+ # TODO: Require farms suck. Do something about it.
15
18
  require dir / 'adapter'
16
- require dir / 'index'
17
19
  require dir / 'attribute'
20
+ require dir / 'index'
21
+ require dir / 'query'
18
22
  require dir / 'resource'
19
-
@@ -1,5 +1,3 @@
1
- require 'benchmark'
2
-
3
1
  module DataMapper
4
2
  module Adapters
5
3
  module Sphinx
@@ -22,48 +20,33 @@ module DataMapper
22
20
  # - adapter Must be :sphinx
23
21
  # - host Hostname (default: localhost)
24
22
  # - port Optional port number (default: 3312)
25
- # - config Optional but recommended path to sphinx config file.
26
23
  #
27
24
  # Alternatively supply a Hash:
28
25
  # DataMapper.setup(:search, {
29
26
  # :adapter => 'sphinx', # required
30
- # :config => './sphinx.conf' # optional. Recommended though.
31
27
  # :host => 'localhost', # optional. Default: localhost
32
28
  # :port => 3312 # optional. Default: 3312
33
- # :managed => true # optional. Self managed searchd server using daemon_controller.
34
29
  # })
35
30
  class Adapter < AbstractAdapter
36
31
 
37
32
  # ==== See
38
- # * DataMapper::Adapters::Sphinx::Config
39
- # * DataMapper::Adapters::Sphinx::Client
33
+ # * DataMapper::Adapters::AbstractAdapter
40
34
  #
41
35
  # ==== Parameters
42
36
  # uri_or_options<URI, DataObject::URI, Addressable::URI, String, Hash, Pathname>::
43
37
  # DataMapper uri or options hash.
44
38
  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)
39
+ options = normalize_options(uri_or_options)
40
+ @client = Riddle::Client.new(options.delete(:host), options.delete(:port))
41
+ options.each{|k, v| @client.method("#{k}=".to_sym).call(v) if @client.respond_to?("#{k}=".to_sym)}
49
42
  end
50
43
 
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
44
  def create(resources) #:nodoc:
62
- true
45
+ 0
63
46
  end
64
47
 
65
48
  def delete(query) #:nodoc:
66
- true
49
+ 0
67
50
  end
68
51
 
69
52
  # Query your Sphinx repository and return all matching documents.
@@ -122,20 +105,6 @@ module DataMapper
122
105
  indexes
123
106
  end
124
107
 
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
108
  # Query sphinx for a list of document IDs.
140
109
  #
141
110
  # ==== Parameters
@@ -147,27 +116,25 @@ module DataMapper
147
116
  def read(query)
148
117
  from = indexes(query.model).map{|index| index.name}.join(', ')
149
118
  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
119
+
120
+ client = @client.dup
121
+ client.match_mode = :extended
122
+ client.filters = search_filters(query) # By attribute.
123
+ client.limit = query.limit.to_i if query.limit
124
+ client.offset = query.offset.to_i if query.offset
156
125
 
157
126
  if order = search_order(query)
158
- options.update(
159
- :sort_mode => :extended,
160
- :sort_by => order
161
- )
127
+ client.sort_mode = :extended
128
+ client.sort_by = order
162
129
  end
163
130
 
164
- res = @client.search(search, from, options)
165
- raise res[:error] unless res[:error].nil?
131
+ result = client.query(search, from)
132
+ raise result[:error] unless result[:error].nil?
166
133
 
167
134
  DataMapper.logger.info(
168
- %q{Sphinx (%.3f): search '%s' in '%s' found %d documents} % [res[:time], search, from, res[:total]]
135
+ %q{Sphinx (%.3f): search '%s' in '%s' found %d documents} % [result[:time], search, from, result[:total]]
169
136
  )
170
- res[:matches].map{|doc| {:id => doc[:doc]}}
137
+ result[:matches].map{|doc| {:id => doc[:doc]}}
171
138
  end
172
139
 
173
140
 
@@ -177,8 +144,8 @@ module DataMapper
177
144
  query.conditions.each do |operator, attribute, value|
178
145
  next unless attribute.kind_of? Sphinx::Attribute
179
146
  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)
147
+ when :eql, :like then attribute.filter(value)
148
+ when :not then attribute.filter(value, false)
182
149
  else raise NotImplementedError.new("Sphinx: Query attributes do not support the #{operator} operator")
183
150
  end
184
151
  end
@@ -196,18 +163,25 @@ module DataMapper
196
163
  by.empty? ? nil : by.join(', ')
197
164
  end
198
165
 
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 }
166
+ # Coerce +uri_or_options+ into a +Hash+ of options.
167
+ #
168
+ # ==== Parameters
169
+ # uri_or_options<URI, DataObject::URI, Addressable::URI, String, Hash, Pathname>::
170
+ # DataMapper uri or options hash.
171
+ #
172
+ # ==== Returns
173
+ # Hash
174
+ def normalize_options(uri_or_options)
175
+ case uri_or_options
176
+ when String, Addressable::URI then DataObjects::URI.parse(uri_or_options).attributes
177
+ when DataObjects::URI then uri_or_options.attributes
178
+ when Pathname then {:path => uri_or_options}
207
179
  else
208
- Array(value)
180
+ uri_or_options[:path] ||= uri_or_options.delete(:config) || uri_or_options.delete(:database)
181
+ uri_or_options
209
182
  end
210
183
  end
184
+
211
185
  end # Adapter
212
186
  end # Sphinx
213
187
 
@@ -1,17 +1,27 @@
1
+ require 'date'
2
+ require 'time'
3
+
1
4
  module DataMapper
2
5
  module Adapters
3
6
  module Sphinx
4
7
 
5
8
  # Sphinx attribute definition.
6
9
  #
7
- # Supports only a subset of DataMapper::Property types that can be used as Sphinx attributes.
10
+ # You must declare attributes as such if you want to use them for sorting or conditions.
11
+ #
12
+ # ==== Notes
13
+ # The following primatives will be used as sql_attr_* types. Some liberty has been taken to accommodate for as
14
+ # many DM primitives as possible.
8
15
  #
9
16
  # TrueClass:: sql_attr_bool
10
17
  # String:: sql_attr_str2ordinal
18
+ # DataMapper::Types::Text:: sql_attr_str2ordinal
11
19
  # Float:: sql_attr_float
12
20
  # Integer:: sql_attr_uint
21
+ # BigDecimal:: sql_attr_float
13
22
  # DateTime:: sql_attr_timestamp
14
23
  # Date:: sql_attr_timestamp
24
+ # Time:: sql_attr_timestamp
15
25
  # DataMapper::Types::Serial:: sql_attr_uint
16
26
  class Attribute < Property
17
27
 
@@ -19,10 +29,10 @@ module DataMapper
19
29
  TYPES = [
20
30
  TrueClass, # sql_attr_bool
21
31
  String, # sql_attr_str2ordinal
22
- # DataMapper::Types::Text,
32
+ DataMapper::Types::Text, # sql_attr_str2ordinal
23
33
  Float, # sql_attr_float
24
34
  Integer, # sql_attr_uint
25
- # BigDecimal, # sql_attr_float?
35
+ BigDecimal, # sql_attr_float
26
36
  DateTime, # sql_attr_timestamp
27
37
  Date, # sql_attr_timestamp
28
38
  Time, # sql_attr_timestamp
@@ -32,6 +42,41 @@ module DataMapper
32
42
  DataMapper::Types::Serial # sql_attr_uint
33
43
  ]
34
44
 
45
+ # Create a riddle client filter from a value.
46
+ #
47
+ # ==== Parameters
48
+ # value<Object>::
49
+ # The filter value to typecast and include/exclude.
50
+ #
51
+ # inclusive<Boolean>::
52
+ # Include or exclude results matching the filter value. Default: inclusive (true).
53
+ #
54
+ # ==== Returns
55
+ # Riddle::Client::Filter::
56
+ def filter(value, inclusive = true)
57
+ # Riddle uses exclusive = false as the default which doesn't read well IMO. Nobody says "Yes I don't want
58
+ # these values" you say "No I don't want these values".
59
+ value = typecast(value)
60
+ value = [value] unless value.quacks_like?([Array, Range])
61
+ Riddle::Client::Filter.new(field, value, !inclusive)
62
+ end
63
+
64
+ # Typecasts the value into a sphinx primitive. Supports ranges or arrays of values.
65
+ #
66
+ # ==== Notes
67
+ # Some loss of precision may occur when casting BigDecimal to Float.
68
+ def typecast(value)
69
+ if value.kind_of?(Range) then Range.new(typecast(value.first), typecast(value.last))
70
+ elsif value.kind_of?(Array) then value.map{|v| typecast(v)}
71
+ elsif primitive == BigDecimal then super(value).to_f
72
+ elsif primitive == DateTime then Time.parse(super(value).to_s).to_i
73
+ elsif primitive == Date then Time.parse(super(value).to_s).to_i
74
+ elsif primitive == Time then super(value).to_i
75
+ else
76
+ super(value) # Good luck
77
+ end
78
+ end
79
+
35
80
  end # Attribute
36
81
  end # Sphinx
37
82
  end # Adapters