shanna-dm-sphinx-adapter 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,10 @@
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
+
1
8
  === 0.4 / 2008-11-21
2
9
 
3
10
  * Fixed broken dm-is-searchable support.
data/Manifest.txt CHANGED
@@ -11,6 +11,7 @@ lib/dm-sphinx-adapter/client.rb
11
11
  lib/dm-sphinx-adapter/config.rb
12
12
  lib/dm-sphinx-adapter/config_parser.rb
13
13
  lib/dm-sphinx-adapter/index.rb
14
+ lib/dm-sphinx-adapter/query.rb
14
15
  lib/dm-sphinx-adapter/resource.rb
15
16
  test/files/dm_sphinx_adapter_test.sql
16
17
  test/files/resource_explicit.rb
@@ -27,5 +28,6 @@ test/test_adapter_vanilla.rb
27
28
  test/test_client.rb
28
29
  test/test_config.rb
29
30
  test/test_config_parser.rb
31
+ test/test_query.rb
30
32
  test/test_type_attribute.rb
31
33
  test/test_type_index.rb
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,15 +2,15 @@
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-24}
9
+ s.date = %q{2008-12-01}
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/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_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/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
15
  s.homepage = %q{http://rubyforge.org/projects/dm-sphinx/}
16
16
  s.rdoc_options = ["--main", "README.txt"]
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.rubyforge_project = %q{dm-sphinx-adapter}
19
19
  s.rubygems_version = %q{1.3.0}
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_type_attribute.rb", "test/test_type_index.rb"]
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
@@ -11,6 +11,7 @@ dir = Pathname(__FILE__).dirname.expand_path / 'dm-sphinx-adapter'
11
11
  require dir / 'config'
12
12
  require dir / 'config_parser'
13
13
  require dir / 'client'
14
+ require dir / 'query'
14
15
  require dir / 'adapter'
15
16
  require dir / 'index'
16
17
  require dir / 'attribute'
@@ -100,7 +100,7 @@ module DataMapper
100
100
  # @param [DataMapper::Query]
101
101
  def read(query)
102
102
  from = indexes(query.model).map{|index| index.name}.join(', ')
103
- search = search_query(query)
103
+ search = Sphinx::Query.new(query).to_s
104
104
  options = {
105
105
  :match_mode => :extended, # TODO: Modes!
106
106
  :filters => search_filters(query) # By attribute.
@@ -124,41 +124,6 @@ module DataMapper
124
124
  res[:matches].map{|doc| {:id => doc[:doc]}}
125
125
  end
126
126
 
127
- ##
128
- # Sphinx search query string from properties (fields).
129
- #
130
- # If the query has no conditions an '' empty string will be generated possibly triggering Sphinx's full scan
131
- # mode.
132
- #
133
- # @see http://www.sphinxsearch.com/doc.html#searching
134
- # @see http://www.sphinxsearch.com/doc.html#conf-docinfo
135
- # @param [DataMapper::Query]
136
- # @return [String]
137
- def search_query(query)
138
- match = []
139
-
140
- if query.conditions.empty?
141
- match << ''
142
- else
143
- # TODO: This needs to be altered by match mode since not everything is supported in different match modes.
144
- query.conditions.each do |operator, property, value|
145
- next if property.kind_of? Sphinx::Attribute # Filters are added elsewhere.
146
- # TODO: Why does my gem riddle differ from the vendor riddle that comes with ts?
147
- # escaped_value = Riddle.escape(value)
148
- escaped_value = value.to_s.gsub(/[\(\)\|\-!@~"&\/]/){|char| "\\#{char}"}
149
- match << case operator
150
- when :eql, :like then "@#{property.field} #{escaped_value}"
151
- when :not then "@#{property.field} -#{escaped_value}"
152
- when :lt, :gt, :lte, :gte
153
- DataMapper.logger.warn('Sphinx: Query properties with lt, gt, lte, gte are treated as .eql')
154
- "@#{name} #{escaped_value}"
155
- when :raw
156
- "#{property}"
157
- end
158
- end
159
- end
160
- match.join(' ')
161
- end
162
127
 
163
128
  ##
164
129
  # Sphinx search query filters from attributes.
@@ -172,10 +137,7 @@ module DataMapper
172
137
  filters << case operator
173
138
  when :eql, :like then Riddle::Client::Filter.new(attribute.name.to_s, filter_value(value))
174
139
  when :not then Riddle::Client::Filter.new(attribute.name.to_s, filter_value(value), true)
175
- else
176
- error = "Sphinx: Query attributes do not support the #{operator} operator"
177
- DataMapper.logger.error(error)
178
- raise error # TODO: RuntimeError subclass and more information about the actual query.
140
+ else raise NotImplementedError.new("Sphinx: Query attributes do not support the #{operator} operator")
179
141
  end
180
142
  end
181
143
  filters
@@ -7,8 +7,6 @@ module DataMapper
7
7
  module Adapters
8
8
  module Sphinx
9
9
  class Client
10
- include Extlib::Assertions
11
-
12
10
  def initialize(uri_or_options = {})
13
11
  @config = Sphinx::Config.new(uri_or_options)
14
12
  end
@@ -0,0 +1,61 @@
1
+ module DataMapper
2
+ module Adapters
3
+ module Sphinx
4
+
5
+ ##
6
+ # Sphinx extended search query string from DataMapper query.
7
+ class Query
8
+ include Extlib::Assertions
9
+
10
+ ##
11
+ # Sphinx extended search query string from DataMapper query.
12
+ #
13
+ # If the query has no conditions an '' empty string will be generated possibly triggering Sphinx's full scan
14
+ # mode.
15
+ #
16
+ # @see http://www.sphinxsearch.com/doc.html#extended-syntax
17
+ # @see http://www.sphinxsearch.com/doc.html#searching
18
+ # @see http://www.sphinxsearch.com/doc.html#conf-docinfo
19
+ # @param [DataMapper::Query]
20
+ def initialize(query)
21
+ assert_kind_of 'query', query, DataMapper::Query
22
+ @query = []
23
+
24
+ if query.conditions.empty?
25
+ @query << ''
26
+ else
27
+ query.conditions.each do |operator, property, value|
28
+ next if property.kind_of? Sphinx::Attribute # Filters are added elsewhere.
29
+ normalized = normalize_value(value)
30
+ @query << case operator
31
+ when :eql, :like then '@%s "%s"' % [property.field.to_s, normalized.join(' ')]
32
+ when :not then '@%s -"%s"' % [property.field.to_s, normalized.join(' ')]
33
+ when :in then '@%s (%s)' % [property.field.to_s, normalized.map{|v| %{"#{v}"}}.join(' | ')]
34
+ when :raw then "#{property}"
35
+ else raise NotImplementedError.new("Sphinx: Query fields do not support the #{operator} operator")
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ ##
42
+ # The extended sphinx query string.
43
+ # @return [String]
44
+ def to_s
45
+ @query.join(' ')
46
+ end
47
+
48
+ protected
49
+ ##
50
+ # Normalize and escape DataMapper query value(s) to escaped sphinx query values.
51
+ # @param [String, Array] value The query value.
52
+ # @return [Array]
53
+ def normalize_value(value)
54
+ [value].flatten.map do |v|
55
+ v.to_s.gsub(/[\(\)\|\-!@~"&\/]/){|char| "\\#{char}"}
56
+ end
57
+ end
58
+ end # Query
59
+ end # Sphinx
60
+ end # Adapters
61
+ end # DataMapper
@@ -0,0 +1,47 @@
1
+ require 'test/unit'
2
+ require 'dm-sphinx-adapter'
3
+ require 'files/resource_explicit'
4
+
5
+ class TestQuery < Test::Unit::TestCase
6
+ def setup
7
+ DataMapper.setup(:default, :adapter => 'sphinx')
8
+ @repository = repository(:default)
9
+ end
10
+
11
+ def test_initialize
12
+ assert_nothing_raised{ query }
13
+ assert_equal '', query.to_s
14
+ end
15
+
16
+ def test_eql
17
+ assert_equal '@name "foo"', query(:name => 'foo').to_s
18
+ assert_equal '@name "foo"', query(:name.eql => 'foo').to_s
19
+ assert_equal '@name "foo"', query(:name.like => 'foo').to_s
20
+ assert_equal '@name "foo bar"', query(:name => %w(foo bar)).to_s
21
+ end
22
+
23
+ def test_not
24
+ assert_equal '@name -"foo"', query(:name.not => 'foo').to_s
25
+ assert_equal '@name -"foo bar"', query(:name.not => %w(foo bar)).to_s
26
+ end
27
+
28
+ def test_in
29
+ assert_equal '@name ("foo" | "bar")', query(:name.in => %w{foo bar}).to_s
30
+ end
31
+
32
+ def test_and
33
+ # When is DM going to switch conditions to an array? :(
34
+ assert /(?:@name "b" )?@name "a"(?: @name "b")?/.match(query(:name.eql => 'a', :name.eql => 'b').to_s)
35
+ end
36
+
37
+ def test_raw
38
+ assert_equal '"foo bar"~10', query(:conditions => ['"foo bar"~10']).to_s
39
+ end
40
+
41
+ protected
42
+ def query(conditions = {})
43
+ DataMapper::Adapters::Sphinx::Query.new(
44
+ DataMapper::Query.new(@repository, Explicit, conditions)
45
+ )
46
+ end
47
+ end # TestQuery
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shanna-dm-sphinx-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.4"
4
+ version: "0.5"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Hanna
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-11-24 00:00:00 -08:00
12
+ date: 2008-12-01 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -65,6 +65,7 @@ files:
65
65
  - lib/dm-sphinx-adapter/config.rb
66
66
  - lib/dm-sphinx-adapter/config_parser.rb
67
67
  - lib/dm-sphinx-adapter/index.rb
68
+ - lib/dm-sphinx-adapter/query.rb
68
69
  - lib/dm-sphinx-adapter/resource.rb
69
70
  - test/files/dm_sphinx_adapter_test.sql
70
71
  - test/files/resource_explicit.rb
@@ -81,6 +82,7 @@ files:
81
82
  - test/test_client.rb
82
83
  - test/test_config.rb
83
84
  - test/test_config_parser.rb
85
+ - test/test_query.rb
84
86
  - test/test_type_attribute.rb
85
87
  - test/test_type_index.rb
86
88
  has_rdoc: true
@@ -119,5 +121,6 @@ test_files:
119
121
  - test/test_client.rb
120
122
  - test/test_config.rb
121
123
  - test/test_config_parser.rb
124
+ - test/test_query.rb
122
125
  - test/test_type_attribute.rb
123
126
  - test/test_type_index.rb