dm-sphinx-adapter 0.4 → 0.5
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.
- data/History.txt +12 -0
- data/Manifest.txt +24 -13
- data/README.txt +44 -28
- data/Rakefile +1 -1
- data/dm-sphinx-adapter.gemspec +7 -7
- data/lib/dm-sphinx-adapter.rb +8 -6
- data/lib/dm-sphinx-adapter/adapter.rb +218 -0
- data/lib/dm-sphinx-adapter/attribute.rb +38 -0
- data/lib/dm-sphinx-adapter/client.rb +109 -0
- data/lib/dm-sphinx-adapter/config.rb +122 -0
- data/lib/dm-sphinx-adapter/config_parser.rb +71 -0
- data/lib/dm-sphinx-adapter/index.rb +38 -0
- data/lib/dm-sphinx-adapter/query.rb +67 -0
- data/lib/dm-sphinx-adapter/resource.rb +103 -0
- data/test/{fixtures/item.sql → files/dm_sphinx_adapter_test.sql} +3 -3
- data/test/{fixtures/item_resource_explicit.rb → files/resource_explicit.rb} +5 -6
- data/test/{fixtures/item_resource_only.rb → files/resource_resource.rb} +4 -5
- data/test/{fixtures/item.rb → files/resource_searchable.rb} +8 -5
- data/test/files/resource_storage_name.rb +11 -0
- data/test/files/resource_vanilla.rb +7 -0
- data/test/{data → files}/sphinx.conf +11 -6
- data/test/test_adapter.rb +38 -0
- data/test/test_adapter_explicit.rb +48 -0
- data/test/test_adapter_resource.rb +25 -0
- data/test/test_adapter_searchable.rb +23 -0
- data/test/test_adapter_vanilla.rb +46 -0
- data/test/test_client.rb +9 -21
- data/test/test_config.rb +58 -24
- data/test/test_config_parser.rb +29 -0
- data/test/test_query.rb +47 -0
- data/test/test_type_attribute.rb +8 -0
- data/test/test_type_index.rb +8 -0
- metadata +38 -19
- data/lib/dm-sphinx-adapter/sphinx_adapter.rb +0 -220
- data/lib/dm-sphinx-adapter/sphinx_attribute.rb +0 -22
- data/lib/dm-sphinx-adapter/sphinx_client.rb +0 -81
- data/lib/dm-sphinx-adapter/sphinx_config.rb +0 -160
- data/lib/dm-sphinx-adapter/sphinx_index.rb +0 -21
- data/lib/dm-sphinx-adapter/sphinx_resource.rb +0 -88
- data/test/helper.rb +0 -7
- 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/
|
9
|
-
lib/dm-sphinx-adapter/
|
10
|
-
lib/dm-sphinx-adapter/
|
11
|
-
lib/dm-sphinx-adapter/
|
12
|
-
lib/dm-sphinx-adapter/
|
13
|
-
lib/dm-sphinx-adapter/
|
14
|
-
|
15
|
-
|
16
|
-
test/
|
17
|
-
test/
|
18
|
-
test/
|
19
|
-
test/
|
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/
|
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
|
-
|
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
|
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
|
-
|
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
|
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
|
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::
|
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::
|
179
|
-
thing missing if you understand the pitfalls and still want to add thinking-sphinx like delta indexing to
|
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
data/dm-sphinx-adapter.gemspec
CHANGED
@@ -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
|
+
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-
|
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/
|
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{
|
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/
|
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
|
data/lib/dm-sphinx-adapter.rb
CHANGED
@@ -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 / '
|
12
|
-
require dir / '
|
13
|
-
require dir / '
|
14
|
-
require dir / '
|
15
|
-
require dir / '
|
16
|
-
require dir / '
|
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
|
+
|