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
@@ -0,0 +1,36 @@
1
+ require File.join(File.dirname(__FILE__), 'helper')
2
+
3
+ class TestAttribute < Test::Unit::TestCase
4
+ context 'DM::A::Sphinx::Attribute instance' do
5
+ should 'typecast DateTime to Integer'
6
+ should 'typecast Date to Integer'
7
+ should 'typecast Time to Integer'
8
+ should 'typecast BigDecimal to Float'
9
+ end
10
+
11
+ context 'DM::A::Sphinx::Resource#attribute class method' do
12
+ setup do
13
+ class ::Resource
14
+ include DataMapper::SphinxResource
15
+ end
16
+ end
17
+
18
+ DataMapper::Adapters::Sphinx::Attribute::TYPES.each do |type|
19
+ should "accept a #{type} type" do
20
+ assert_nothing_raised do
21
+ Resource.class_eval do
22
+ attribute :name, type
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ should 'raise ArgumentError for unsupported type' do
29
+ assert_raise(ArgumentError) do
30
+ Resource.class_eval do
31
+ attribute :name, Test::Unit::TestCase
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,30 @@
1
+ require File.join(File.dirname(__FILE__), 'helper')
2
+
3
+ class TestIndex < Test::Unit::TestCase
4
+ context 'DM::A::Sphinx::Index instance' do
5
+ should 'respond to delta?'
6
+ end
7
+
8
+ context 'DM::A::Sphinx::Resource class' do
9
+ setup do
10
+ class ::Resource
11
+ include DataMapper::SphinxResource
12
+ end
13
+ end
14
+
15
+ context '#index method' do
16
+ should 'append an index' do
17
+ assert_nothing_raised do
18
+ Resource.class_eval do
19
+ index :name
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ context '#sphinx_indexes method' do
26
+ should 'return DM::A::Sphinx::Index objects'
27
+ should 'return delta indexes at the end of the list'
28
+ end
29
+ end
30
+ end
data/test/test_query.rb CHANGED
@@ -1,47 +1,62 @@
1
- require 'test/unit'
2
- require 'dm-sphinx-adapter'
3
- require 'files/resource_explicit'
1
+ require File.join(File.dirname(__FILE__), 'helper')
4
2
 
5
3
  class TestQuery < Test::Unit::TestCase
6
- def setup
7
- DataMapper.setup(:default, :adapter => 'sphinx')
8
- @repository = repository(:default)
9
- end
4
+ context 'DM::A::Sphinx::Query conditions' do
5
+ setup do
6
+ DataMapper.setup(:adapter, :adapter => 'sphinx')
7
+ load File.join(File.dirname(__FILE__), 'files', 'model.rb')
8
+ @adapter = repository(:adapter)
9
+ @resource = Item
10
+ end
10
11
 
11
- def test_initialize
12
- assert_nothing_raised{ query }
13
- assert_equal '', query.to_s
14
- end
12
+ should 'treat nil operator as extended field match' do
13
+ assert_equal '@t_string "foo"', query_string(:t_string => 'foo')
14
+ end
15
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
16
+ should 'treat .eql operator as extended field match' do
17
+ assert_equal '@t_string "foo"', query_string(:t_string.eql => 'foo')
18
+ end
22
19
 
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
20
+ should 'treat .like operator as extended field match' do
21
+ assert_equal '@t_string "foo"', query_string(:t_string.like => 'foo')
22
+ end
27
23
 
28
- def test_in
29
- assert_equal '@name ("foo" | "bar")', query(:name.in => %w{foo bar}).to_s
30
- end
24
+ should 'treat Array as extended field AND match' do
25
+ assert_equal '@t_string "foo bar"', query_string(:t_string => %w{foo bar})
26
+ end
31
27
 
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
28
+ should 'treat .not opeartor as extended field NOT match' do
29
+ assert_equal '@t_string -"foo"', query_string(:t_string.not => 'foo')
30
+ end
31
+
32
+ should 'treat Array .not operator as extended field NOT match' do
33
+ assert_equal '@t_string -"foo bar"', query_string(:t_string.not => %w{foo bar})
34
+ end
36
35
 
37
- def test_raw
38
- assert_equal '"foo bar"~10', query(:conditions => ['"foo bar"~10']).to_s
36
+ should 'treat .in operator as extended OR match' do
37
+ assert_equal '@t_string ("foo" | "bar")', query_string(:t_string.in => %w{foo bar})
38
+ end
39
+
40
+ should 'treat multiple .eql operators as AND search' do
41
+ # When is DM going to switch conditions to an array? :(
42
+ assert /(?:@t_string "b" )?@t_string "a"(?: @t_string "b")?/.match(
43
+ query_string(:t_string.eql => 'a', :t_string.eql => 'b')
44
+ )
45
+ end
46
+
47
+ should 'leave raw conditions as they are' do
48
+ assert_equal '"foo bar"~10', query_string(:conditions => ['"foo bar"~10'])
49
+ end
39
50
  end
40
51
 
41
52
  protected
42
53
  def query(conditions = {})
43
54
  DataMapper::Adapters::Sphinx::Query.new(
44
- DataMapper::Query.new(@repository, Explicit, conditions)
55
+ DataMapper::Query.new(@adapter, @resource, conditions)
45
56
  )
46
57
  end
47
- end # TestQuery
58
+
59
+ def query_string(conditions = {})
60
+ query(conditions).to_s
61
+ end
62
+ end
@@ -0,0 +1,17 @@
1
+ require File.join(File.dirname(__FILE__), 'helper')
2
+
3
+ class TestResource < Test::Unit::TestCase
4
+ context 'DM::A::Sphinx::Resource module' do
5
+ setup do
6
+ class ::Resource
7
+ include DataMapper::SphinxResource
8
+ end
9
+ end
10
+
11
+ [:index, :sphinx_indexes, :attribute, :sphinx_attributes].each do |method|
12
+ should "respond to #{method}" do
13
+ assert_respond_to Resource, method
14
+ end
15
+ end
16
+ end
17
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dm-sphinx-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.5"
4
+ version: "0.6"
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-12-01 00:00:00 +11:00
12
+ date: 2008-12-13 00:00:00 +11:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -22,16 +22,6 @@ dependencies:
22
22
  - !ruby/object:Gem::Version
23
23
  version: 0.9.7
24
24
  version:
25
- - !ruby/object:Gem::Dependency
26
- name: riddle
27
- type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ~>
32
- - !ruby/object:Gem::Version
33
- version: "0.9"
34
- version:
35
25
  - !ruby/object:Gem::Dependency
36
26
  name: hoe
37
27
  type: :development
@@ -64,30 +54,23 @@ files:
64
54
  - lib/dm-sphinx-adapter.rb
65
55
  - lib/dm-sphinx-adapter/adapter.rb
66
56
  - lib/dm-sphinx-adapter/attribute.rb
67
- - lib/dm-sphinx-adapter/client.rb
68
- - lib/dm-sphinx-adapter/config.rb
69
- - lib/dm-sphinx-adapter/config_parser.rb
70
57
  - lib/dm-sphinx-adapter/index.rb
71
58
  - lib/dm-sphinx-adapter/query.rb
72
59
  - lib/dm-sphinx-adapter/resource.rb
73
- - test/files/dm_sphinx_adapter_test.sql
74
- - test/files/resource_explicit.rb
75
- - test/files/resource_resource.rb
76
- - test/files/resource_searchable.rb
77
- - test/files/resource_storage_name.rb
78
- - test/files/resource_vanilla.rb
79
- - test/files/sphinx.conf
60
+ - lib/riddle.rb
61
+ - lib/riddle/client.rb
62
+ - lib/riddle/client/filter.rb
63
+ - lib/riddle/client/message.rb
64
+ - lib/riddle/client/response.rb
65
+ - test/files/model.rb
66
+ - test/files/mysql5.sphinx.conf
67
+ - test/files/mysql5.sql
68
+ - test/helper.rb
80
69
  - test/test_adapter.rb
81
- - test/test_adapter_explicit.rb
82
- - test/test_adapter_resource.rb
83
- - test/test_adapter_searchable.rb
84
- - test/test_adapter_vanilla.rb
85
- - test/test_client.rb
86
- - test/test_config.rb
87
- - test/test_config_parser.rb
70
+ - test/test_attribute.rb
71
+ - test/test_index.rb
88
72
  - test/test_query.rb
89
- - test/test_type_attribute.rb
90
- - test/test_type_index.rb
73
+ - test/test_resource.rb
91
74
  has_rdoc: true
92
75
  homepage: http://dm-sphinx.rubyforge.org
93
76
  post_install_message:
@@ -111,19 +94,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
94
  requirements: []
112
95
 
113
96
  rubyforge_project: dm-sphinx-adapter
114
- rubygems_version: 1.3.0
97
+ rubygems_version: 1.3.1
115
98
  signing_key:
116
99
  specification_version: 2
117
100
  summary: A DataMapper Sphinx adapter.
118
101
  test_files:
119
102
  - test/test_adapter.rb
120
- - test/test_adapter_explicit.rb
121
- - test/test_adapter_resource.rb
122
- - test/test_adapter_searchable.rb
123
- - test/test_adapter_vanilla.rb
124
- - test/test_client.rb
125
- - test/test_config.rb
126
- - test/test_config_parser.rb
103
+ - test/test_attribute.rb
104
+ - test/test_index.rb
127
105
  - test/test_query.rb
128
- - test/test_type_attribute.rb
129
- - test/test_type_index.rb
106
+ - test/test_resource.rb
@@ -1,109 +0,0 @@
1
- require 'rubygems'
2
-
3
- gem 'riddle', '~> 0.9'
4
- require 'riddle'
5
-
6
- module DataMapper
7
- module Adapters
8
- module Sphinx
9
- # Client wrapper for Riddle::Client.
10
- #
11
- # * Simple interface to +searchd+ *and* +indexer+.
12
- # * Can read +searchd+ configuration options from your sphinx configuration file.
13
- # * Managed +searchd+ using +daemon_controller+ for on demand daemon control in development.
14
- class Client
15
-
16
- # ==== Parameters
17
- # uri_or_options<URI, DataObject::URI, Addressable::URI, String, Hash, Pathname>::
18
- # DataMapper uri or options hash.
19
- def initialize(uri_or_options = {})
20
- @config = Sphinx::Config.new(uri_or_options)
21
- end
22
-
23
- # Search one or more indexes.
24
- #
25
- # ==== See
26
- # * Riddle::Client
27
- #
28
- # ==== Parameters
29
- # query<String>:: A sphinx query string.
30
- # indexes<Array, String>:: Indexes to search. Default is '*' all.
31
- # options<Hash>:: Any attributes supported by the Riddle::Client.
32
- #
33
- # ==== Returns
34
- # Hash:: Riddle::Client#query response struct.
35
- def search(query, indexes = '*', options = {})
36
- indexes = indexes.join(' ') if indexes.kind_of?(Array)
37
-
38
- client = Riddle::Client.new(@config.address, @config.port)
39
- options.each{|k, v| client.method("#{k}=".to_sym).call(v) if client.respond_to?("#{k}=".to_sym)}
40
- client.query(query, indexes.to_s)
41
- end
42
-
43
- # Index one or more indexes.
44
- #
45
- # ==== Parameters
46
- # indexes<Array, String>:: Indexes to index (and rotate). Defaults to --all if indexes is +nil+ or '*'.
47
- def index(indexes = nil)
48
- indexes = indexes.join(' ') if indexes.kind_of?(Array)
49
-
50
- command = @config.indexer_bin
51
- command << " --rotate" if running?
52
- command << ((indexes.nil? || indexes == '*') ? ' --all' : " #{indexes.to_s}")
53
- warn "Sphinx: Indexer #{$1}" if `#{command}` =~ /(?:error|fatal|warning):?\s*([^\n]+)/i
54
- end
55
-
56
- protected
57
- # Is a +searchd+ daemon running on the configured address and port.
58
- #
59
- # ==== Notes
60
- # This is a simple TCPSocket test. It may not be your +searchd+ deamon or even a +searchd+ daemon at all if
61
- # your configuration is wrong or another +searchd+ daemon is listen on that port already.
62
- #
63
- # ==== Returns
64
- # Boolean
65
- def running?
66
- !!TCPSocket.new(@config.address, @config.port) rescue nil
67
- end
68
- end # Client
69
-
70
- # Managed searchd if you don't already have god/monit doing the job for you.
71
- #
72
- # Requires you have +daemon_controller+ installed.
73
- #
74
- # ==== See
75
- # * http://github.com/FooBarWidget/daemon_controller/tree/master
76
- class ManagedClient < Client
77
-
78
- # ==== See
79
- # * DataMapper::Adapters::Sphinx::Client#new
80
- def initialize(url_or_options = {})
81
- super
82
-
83
- require 'daemon_controller'
84
- @client = DaemonController.new(
85
- :identifier => 'Sphinx searchd',
86
- :start_command => @config.searchd_bin,
87
- :stop_command => "#{@config.searchd_bin} --stop",
88
- :ping_command => method(:running?),
89
- :pid_file => @config.pid_file,
90
- :log_file => @config.log
91
- )
92
- end
93
-
94
- # Start the +searchd+ daemon if it isn't already running then search.
95
- #
96
- # ==== See
97
- # * DataMapper::Adapters::Sphinx::Client#search
98
- def search(*args)
99
- @client.connect{super}
100
- end
101
-
102
- # Stop the +searchd+ daemon if it's running.
103
- def stop
104
- @client.stop if @client.running?
105
- end
106
- end # ManagedClient
107
- end # Sphinx
108
- end # Adapters
109
- end # DataMapper
@@ -1,122 +0,0 @@
1
- require 'rubygems'
2
-
3
- gem 'extlib', '~> 0.9.7'
4
- require 'extlib'
5
-
6
- module DataMapper
7
- module Adapters
8
- module Sphinx
9
- class Config
10
- include Extlib::Assertions
11
-
12
- # Configuration option.
13
- attr_reader :config, :address, :log, :port
14
-
15
- # Sphinx configuration options.
16
- #
17
- # This class just gives you access to handy searchd {} configuration options. If a sphinx configuration file
18
- # is passed and can be parsed +searchd+ options will be set straight from the file.
19
- #
20
- # ==== Notes
21
- # Option precedence is:
22
- # * The options hash.
23
- # * The configuration file.
24
- # * Sphinx defaults.
25
- #
26
- # ==== See
27
- # http://www.sphinxsearch.com/doc.html#confgroup-searchd
28
- #
29
- # ==== Parameters
30
- # uri_or_options<URI, DataObject::URI, Addressable::URI, String, Hash, Pathname>::
31
- # DataMapper uri or options hash.
32
- def initialize(uri_or_options = {})
33
- assert_kind_of 'uri_or_options', uri_or_options, Addressable::URI, DataObjects::URI, Hash, String, Pathname
34
-
35
- options = normalize_options(uri_or_options)
36
- config = parse_config("#{options[:path]}") # Pathname#to_s is broken?
37
- @address = options[:host] || config['address'] || '0.0.0.0'
38
- @port = options[:port] || config['port'] || 3312
39
- @log = options[:log] || config['log'] || 'searchd.log'
40
- @pid_file = options[:pid_file] || config['pid_file']
41
- end
42
-
43
- # Indexer binary full path name and config argument.
44
- #
45
- # ==== Parameters
46
- # use_config<Boolean>:: Return <tt>--config path/to/config.conf</tt> as part of string. Default +true+.
47
- #
48
- # ==== Returns
49
- # String
50
- def indexer_bin(use_config = true)
51
- path = 'indexer' # TODO: Real.
52
- path << " --config #{config}" if config
53
- path
54
- end
55
-
56
- # Searchd binary full path name and config argument.
57
- #
58
- # ==== Parameters
59
- # use_config<Boolean>:: Return <tt>--config path/to/config.conf</tt> as part of string. Default +true+.
60
- #
61
- # ==== Returns
62
- # String
63
- def searchd_bin(use_config = true)
64
- path = 'searchd' # TODO: Real.
65
- path << " --config #{config}" if config
66
- path
67
- end
68
-
69
- # Full path to pid_file.
70
- #
71
- # ==== Raises
72
- # RuntimeError:: If a pid file was not read or set. pid_file is a mandatory searchd option in a sphinx
73
- # configuration file.
74
- def pid_file
75
- @pid_file or raise "Mandatory pid_file option missing from searchd configuration."
76
- end
77
-
78
- protected
79
- # Coerce +uri_or_options+ into a +Hash+ of options.
80
- #
81
- # ==== Parameters
82
- # uri_or_options<URI, DataObject::URI, Addressable::URI, String, Hash, Pathname>::
83
- # DataMapper uri or options hash.
84
- #
85
- # ==== Returns
86
- # Hash
87
- def normalize_options(uri_or_options)
88
- case uri_or_options
89
- when String, Addressable::URI then DataObjects::URI.parse(uri_or_options).attributes
90
- when DataObjects::URI then uri_or_options.attributes
91
- when Pathname then {:path => uri_or_options}
92
- else
93
- uri_or_options[:path] ||= uri_or_options.delete(:config) || uri_or_options.delete(:database)
94
- uri_or_options
95
- end
96
- end
97
-
98
- # Reads your sphinx configuration file if given.
99
- #
100
- # Also searches default sphinx configuration locations for a config file to parse.
101
- #
102
- # ==== See
103
- # * DataMapper::Adapters::Sphinx::ConfigParser
104
- #
105
- # ==== Parameters
106
- # path<String>:: Path to your configuration file.
107
- #
108
- # ==== Returns
109
- # Hash
110
- def parse_config(path)
111
- paths = []
112
- paths.push(path, path.gsub(%r{^/}, './'), path.gsub(%r{^\./}, '/')) unless path.blank?
113
- paths.push('/usr/local/etc/sphinx.conf', './sphinx.conf')
114
- paths.map!{|path| Pathname.new(path).expand_path}
115
-
116
- @config = paths.find{|path| path.readable? && `#{indexer_bin} --config #{path}` !~ /fatal|error/i}
117
- @config ? ConfigParser.parse(@config) : {}
118
- end
119
- end # Config
120
- end # Sphinx
121
- end # Adapters
122
- end # DataMapper