dm-sphinx-adapter 0.5 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
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