rlibsphinxclient 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGELOG.rdoc +18 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +151 -0
  5. data/Rakefile +39 -0
  6. data/VERSION +1 -0
  7. data/ext/extconf.rb +20 -0
  8. data/ext/rlibsphinxclient.i +314 -0
  9. data/ext/rlibsphinxclient_wrap.c +5931 -0
  10. data/init.rb +1 -0
  11. data/lib/sphinx.rb +22 -0
  12. data/lib/sphinx/client.rb +1070 -0
  13. data/lib/sphinx/fast_client.rb +184 -0
  14. data/lib/sphinx/request.rb +49 -0
  15. data/lib/sphinx/response.rb +69 -0
  16. data/lib/sphinx/safe_executor.rb +11 -0
  17. data/lib/sphinx/timeout.rb +9 -0
  18. data/rlibsphinxclient.gemspec +117 -0
  19. data/spec/client_response_spec.rb +135 -0
  20. data/spec/client_spec.rb +548 -0
  21. data/spec/fixtures/default_search.php +8 -0
  22. data/spec/fixtures/default_search_index.php +8 -0
  23. data/spec/fixtures/excerpt_custom.php +11 -0
  24. data/spec/fixtures/excerpt_default.php +8 -0
  25. data/spec/fixtures/excerpt_flags.php +11 -0
  26. data/spec/fixtures/field_weights.php +9 -0
  27. data/spec/fixtures/filter.php +9 -0
  28. data/spec/fixtures/filter_exclude.php +9 -0
  29. data/spec/fixtures/filter_float_range.php +9 -0
  30. data/spec/fixtures/filter_float_range_exclude.php +9 -0
  31. data/spec/fixtures/filter_range.php +9 -0
  32. data/spec/fixtures/filter_range_exclude.php +9 -0
  33. data/spec/fixtures/filter_ranges.php +10 -0
  34. data/spec/fixtures/filters.php +10 -0
  35. data/spec/fixtures/filters_different.php +13 -0
  36. data/spec/fixtures/geo_anchor.php +9 -0
  37. data/spec/fixtures/group_by_attr.php +9 -0
  38. data/spec/fixtures/group_by_attrpair.php +9 -0
  39. data/spec/fixtures/group_by_day.php +9 -0
  40. data/spec/fixtures/group_by_day_sort.php +9 -0
  41. data/spec/fixtures/group_by_month.php +9 -0
  42. data/spec/fixtures/group_by_week.php +9 -0
  43. data/spec/fixtures/group_by_year.php +9 -0
  44. data/spec/fixtures/group_distinct.php +10 -0
  45. data/spec/fixtures/id_range.php +9 -0
  46. data/spec/fixtures/id_range64.php +9 -0
  47. data/spec/fixtures/index_weights.php +9 -0
  48. data/spec/fixtures/keywords.php +8 -0
  49. data/spec/fixtures/limits.php +9 -0
  50. data/spec/fixtures/limits_cutoff.php +9 -0
  51. data/spec/fixtures/limits_max.php +9 -0
  52. data/spec/fixtures/limits_max_cutoff.php +9 -0
  53. data/spec/fixtures/match_all.php +9 -0
  54. data/spec/fixtures/match_any.php +9 -0
  55. data/spec/fixtures/match_boolean.php +9 -0
  56. data/spec/fixtures/match_extended.php +9 -0
  57. data/spec/fixtures/match_extended2.php +9 -0
  58. data/spec/fixtures/match_fullscan.php +9 -0
  59. data/spec/fixtures/match_phrase.php +9 -0
  60. data/spec/fixtures/max_query_time.php +9 -0
  61. data/spec/fixtures/miltiple_queries.php +12 -0
  62. data/spec/fixtures/ranking_bm25.php +9 -0
  63. data/spec/fixtures/ranking_none.php +9 -0
  64. data/spec/fixtures/ranking_proximity_bm25.php +9 -0
  65. data/spec/fixtures/ranking_wordcount.php +9 -0
  66. data/spec/fixtures/retries.php +9 -0
  67. data/spec/fixtures/retries_delay.php +9 -0
  68. data/spec/fixtures/sort_attr_asc.php +9 -0
  69. data/spec/fixtures/sort_attr_desc.php +9 -0
  70. data/spec/fixtures/sort_expr.php +9 -0
  71. data/spec/fixtures/sort_extended.php +9 -0
  72. data/spec/fixtures/sort_relevance.php +9 -0
  73. data/spec/fixtures/sort_time_segments.php +9 -0
  74. data/spec/fixtures/sphinxapi.php +1181 -0
  75. data/spec/fixtures/update_attributes.php +8 -0
  76. data/spec/fixtures/weights.php +9 -0
  77. data/spec/sphinx/sphinx.conf +67 -0
  78. data/spec/sphinx/sphinx_test.sql +86 -0
  79. metadata +133 -0
@@ -0,0 +1,184 @@
1
+ # = fast_client.rb - Wrapper for pure C Sphinx client API
2
+ #
3
+ # Author:: Dmytro Shteflyuk <mailto:kpumuk@kpumuk.info>.
4
+ # Copyright:: Copyright (c) 2009 Dmytro Shteflyuk
5
+ # License:: Distributes under the MIT license.
6
+ # Version:: 0.2.2
7
+ # Website:: http://kpumuk.info/projects/ror-plugins/sphinx
8
+ #
9
+ # This library is distributed under the terms of the MIT license.
10
+
11
+ # == Sphinx Client API
12
+ #
13
+ # The Sphinx Client API is used to communicate with <tt>searchd</tt>
14
+ # daemon and get search results from Sphinx.
15
+ #
16
+ # === Usage
17
+ #
18
+ # begin
19
+ # sphinx = Sphinx::FastClient.new
20
+ # result = sphinx.Query('test')
21
+ # ids = result['matches'].map { |match| match['id'] }.join(',')
22
+ # posts = Post.find :all, :conditions => "id IN (#{ids})"
23
+ #
24
+ # docs = posts.map(&:body)
25
+ # excerpts = sphinx.BuildExcerpts(docs, 'index', 'test')
26
+ # ensure
27
+ # sphinx.destroy
28
+ # end
29
+
30
+ module Sphinx
31
+
32
+ # A wrapper for pure C Sphinx client API.
33
+ class FastClient
34
+ Lib = Rlibsphinxclient
35
+
36
+ # Constructs the <tt>Sphinx::FastClient</tt> object and sets options to their default values.
37
+ def initialize
38
+ @sphinx = Lib.sphinx_create(true)
39
+ end
40
+
41
+ # Destroys all internal memory buffers. Should be called when Sphinx API is no needed.
42
+ def destroy
43
+ Lib.sphinx_destroy(@sphinx)
44
+ @sphinx = nil
45
+ end
46
+
47
+ # See Client.GetLastError for details.
48
+ def GetLastError
49
+ Lib.sphinx_error(@sphinx)
50
+ end
51
+
52
+ # See Client.GetLastWarning for details.
53
+ def GetLastWarning
54
+ Lib.sphinx_warning(@sphinx)
55
+ end
56
+
57
+ # See Client.SetServer for details.
58
+ def SetServer(host, port)
59
+ Lib.sphinx_set_server(@sphinx, host, port)
60
+ end
61
+
62
+ def SetConnectionTimeout(seconds)
63
+ Lib.sphinx_set_connect_timeout(@sphinx, seconds)
64
+ end
65
+
66
+ # See Client.SetLimits for details.
67
+ def SetLimits(offset, limit, max_matches = 0, cutoff = 0)
68
+ Lib.sphinx_set_limits(@sphinx, offset, limit, max_matches, cutoff)
69
+ end
70
+
71
+ # See Client.SetMaxQueryTime for details.
72
+ def SetMaxQueryTime(max_query_time)
73
+ Lib.sphinx_set_max_query_time(@sphinx, max_query_time)
74
+ end
75
+
76
+ # See Client.SetMatchMode for details.
77
+ def SetMatchMode(mode)
78
+ mode = Lib.const_get("SPH_MATCH_#{mode.to_s.upcase}") if mode.is_a? Symbol
79
+ Lib.sphinx_set_match_mode(@sphinx, mode)
80
+ end
81
+
82
+ # See Client.SetRankingMode for details.
83
+ def SetRankingMode(ranker)
84
+ ranker = Lib.const_get("SPH_RANK_#{ranker.to_s.upcase}") if ranker.is_a? Symbol
85
+ Lib.sphinx_set_ranking_mode(@sphinx, ranker)
86
+ end
87
+
88
+ # See Client.SetSortMode for details.
89
+ def SetSortMode(mode, sortby = '')
90
+ mode = Lib.const_get("SPH_SORT_#{mode.to_s.upcase}") if mode.is_a? Symbol
91
+ Lib.sphinx_set_sort_mode(@sphinx, mode, sortby)
92
+ end
93
+
94
+ # See Client.SetFieldWeights for details.
95
+ def SetFieldWeights(weights)
96
+ Lib.sphinx_set_field_weights(@sphinx, weights.size, weights.keys, weights.values)
97
+ end
98
+
99
+ # See Client.SetIndexWeights for details.
100
+ def SetIndexWeights(weights)
101
+ Lib.sphinx_set_index_weights(@sphinx, weights.size, weights.keys, weights.values)
102
+ end
103
+
104
+ # See Client.SetIDRange for details.
105
+ def SetIDRange(min, max)
106
+ Lib.sphinx_set_id_range(@sphinx, min, max)
107
+ end
108
+
109
+ # See Client.SetFilter for details.
110
+ def SetFilter(attribute, values, exclude = false)
111
+ Lib.sphinx_add_filter(@sphinx, attribute, values.length, values, exclude)
112
+ end
113
+
114
+ # See Client.SetFilterRange for details.
115
+ def SetFilterRange(attribute, min, max, exclude = false)
116
+ Lib.sphinx_add_filter_range(@sphinx, attribute, min, max, exclude)
117
+ end
118
+
119
+ # See Client.SetFilterFloatRange for details.
120
+ def SetFilterFloatRange(attribute, min, max, exclude = false)
121
+ Lib.sphinx_add_filter_float_range(@sphinx, attribute, min, max, exclude)
122
+ end
123
+
124
+ # See Client.SetGeoAnchor for details.
125
+ def SetGeoAnchor(attrlat, attrlong, lat, long)
126
+ Lib.sphinx_set_geoanchor(@sphinx, attrlat, attrlong, lat, long)
127
+ end
128
+
129
+ # See Client.SetGroupBy for details.
130
+ def SetGroupBy(attribute, func, groupsort = '@group desc')
131
+ Lib.sphinx_set_groupby(@sphinx, attribute, func, groupsort)
132
+ end
133
+
134
+ # See Client.SetGroupDistinct for details.
135
+ def SetGroupDistinct(attribute)
136
+ Lib.sphinx_set_groupby_distinct(@sphinx, attribute)
137
+ end
138
+
139
+ # See Client.SetRetries for details.
140
+ def SetRetries(count, delay = 0)
141
+ Lib.sphinx_set_retries(@sphinx, count, delay)
142
+ end
143
+
144
+ # See Client.ResetFilters for details.
145
+ def ResetFilters
146
+ Lib.sphinx_reset_filters(@sphinx)
147
+ end
148
+
149
+ # See Client.ResetGroupBy for details.
150
+ def ResetGroupBy
151
+ Lib.sphinx_reset_groupby(@sphinx)
152
+ end
153
+
154
+ # See Client.Query for details.
155
+ def Query(query, index = '*', comment = '')
156
+ Lib.sphinx_query(@sphinx, query, index, comment)
157
+ end
158
+
159
+ # See Client.AddQuery for details.
160
+ def AddQuery(query, index = '*', comment = '')
161
+ Lib.sphinx_add_query(@sphinx, query, index, comment)
162
+ end
163
+
164
+ # See Client.RunQueries for details.
165
+ def RunQueries
166
+ Lib.sphinx_run_queries(@sphinx)
167
+ end
168
+
169
+ # See Client.BuildExcerpts for details.
170
+ def BuildExcerpts(docs, index, words, opts = {})
171
+ Lib.sphinx_build_excerpts(@sphinx, docs.size, docs, index, words, opts)
172
+ end
173
+
174
+ # See Client.BuildKeywords for details.
175
+ def BuildKeywords(query, index, hits)
176
+ Lib.sphinx_build_keywords(@sphinx, query, index, hits)
177
+ end
178
+
179
+ # See Client.UpdateAttributes for details.
180
+ def UpdateAttributes(index, attrs, values, mva = false)
181
+ Lib.sphinx_update_attributes(@sphinx, index, attrs.size, attrs, values.size, values.keys, values.values.flatten)
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,49 @@
1
+ module Sphinx
2
+ # Pack ints, floats, strings, and arrays to internal representation
3
+ # needed by Sphinx search engine.
4
+ class Request
5
+ # Initialize new request.
6
+ def initialize
7
+ @request = ''
8
+ end
9
+
10
+ # Put int(s) to request.
11
+ def put_int(*ints)
12
+ ints.each { |i| @request << [i].pack('N') }
13
+ end
14
+
15
+ # Put 64-bit int(s) to request.
16
+ def put_int64(*ints)
17
+ ints.each { |i| @request << [i >> 32, i & ((1 << 32) - 1)].pack('NN') }
18
+ end
19
+
20
+ # Put 64-bit int(s) to request (Sphinx 0.9.9 compatible version).
21
+ def put_int64_new(*ints)
22
+ ints.each { |i| @request << [i].pack('q').reverse }
23
+ end
24
+
25
+ # Put string(s) to request (first length, then the string itself).
26
+ def put_string(*strings)
27
+ strings.each { |s| @request << [s.length].pack('N') + s }
28
+ end
29
+
30
+ # Put float(s) to request.
31
+ def put_float(*floats)
32
+ floats.each do |f|
33
+ t1 = [f].pack('f') # machine order
34
+ t2 = t1.unpack('L*').first # int in machine order
35
+ @request << [t2].pack('N')
36
+ end
37
+ end
38
+
39
+ # Put array of ints to request (first length, then the array itself)
40
+ def put_int_array(arr)
41
+ put_int arr.length, *arr
42
+ end
43
+
44
+ # Returns the entire message
45
+ def to_s
46
+ @request
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,69 @@
1
+ module Sphinx
2
+ # Unpack internal Sphinx representation of ints, floats, strings, and arrays.
3
+ # needed by Sphinx search engine.
4
+ class Response
5
+ # Initialize new request.
6
+ def initialize(response)
7
+ @response = response
8
+ @position = 0
9
+ @size = response.length
10
+ end
11
+
12
+ # Gets current stream position.
13
+ def position
14
+ @position
15
+ end
16
+
17
+ # Gets response size.
18
+ def size
19
+ @size
20
+ end
21
+
22
+ # Returns <tt>true</tt> when response stream is out.
23
+ def eof?
24
+ @position >= @size
25
+ end
26
+
27
+ # Get int from stream.
28
+ def get_int
29
+ raise EOFError if @position + 4 > @size
30
+ value = @response[@position, 4].unpack('N*').first
31
+ @position += 4
32
+ return value
33
+ end
34
+
35
+ # Get 64-bit int from stream.
36
+ def get_int64
37
+ raise EOFError if @position + 8 > @size
38
+ hi, lo = @response[@position, 8].unpack('N*N*')
39
+ @position += 8
40
+ return (hi << 32) + lo
41
+ end
42
+
43
+ # Get array of <tt>count</tt> ints from stream.
44
+ def get_ints(count)
45
+ length = 4 * count
46
+ raise EOFError if @position + length > @size
47
+ values = @response[@position, length].unpack('N*' * count)
48
+ @position += length
49
+ return values
50
+ end
51
+
52
+ # Get string from stream.
53
+ def get_string
54
+ length = get_int
55
+ raise EOFError if @position + length > @size
56
+ value = length > 0 ? @response[@position, length] : ''
57
+ @position += length
58
+ return value
59
+ end
60
+
61
+ # Get float from stream.
62
+ def get_float
63
+ raise EOFError if @position + 4 > @size
64
+ uval = @response[@position, 4].unpack('N*').first;
65
+ @position += 4
66
+ return ([uval].pack('L')).unpack('f*').first
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,11 @@
1
+ module Sphinx
2
+ class SafeExecutor
3
+ def self.execute(timeout = 5, attempts = 3, &block)
4
+ Sphinx::Timeout.timeout(timeout, &block)
5
+ rescue ::Timeout::Error
6
+ attempts -= 1
7
+ raise if attempts <= 0
8
+ retry
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module Sphinx
2
+ begin
3
+ require 'system_timer'
4
+ Timeout = ::SystemTimer
5
+ rescue LoadError
6
+ require 'timeout'
7
+ Timeout = ::Timeout
8
+ end
9
+ end
@@ -0,0 +1,117 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rlibsphinxclient}
8
+ s.version = "0.2.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Dmytro Shteflyuk"]
12
+ s.date = %q{2009-10-15}
13
+ s.email = %q{kpumuk@kpumuk.info}
14
+ s.extensions = ["ext/extconf.rb"]
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "CHANGELOG.rdoc",
21
+ "MIT-LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "ext/extconf.rb",
26
+ "ext/rlibsphinxclient.i",
27
+ "ext/rlibsphinxclient_wrap.c",
28
+ "init.rb",
29
+ "lib/sphinx.rb",
30
+ "lib/sphinx/client.rb",
31
+ "lib/sphinx/fast_client.rb",
32
+ "lib/sphinx/request.rb",
33
+ "lib/sphinx/response.rb",
34
+ "lib/sphinx/safe_executor.rb",
35
+ "lib/sphinx/timeout.rb",
36
+ "rlibsphinxclient.gemspec",
37
+ "spec/client_response_spec.rb",
38
+ "spec/client_spec.rb",
39
+ "spec/fixtures/default_search.php",
40
+ "spec/fixtures/default_search_index.php",
41
+ "spec/fixtures/excerpt_custom.php",
42
+ "spec/fixtures/excerpt_default.php",
43
+ "spec/fixtures/excerpt_flags.php",
44
+ "spec/fixtures/field_weights.php",
45
+ "spec/fixtures/filter.php",
46
+ "spec/fixtures/filter_exclude.php",
47
+ "spec/fixtures/filter_float_range.php",
48
+ "spec/fixtures/filter_float_range_exclude.php",
49
+ "spec/fixtures/filter_range.php",
50
+ "spec/fixtures/filter_range_exclude.php",
51
+ "spec/fixtures/filter_ranges.php",
52
+ "spec/fixtures/filters.php",
53
+ "spec/fixtures/filters_different.php",
54
+ "spec/fixtures/geo_anchor.php",
55
+ "spec/fixtures/group_by_attr.php",
56
+ "spec/fixtures/group_by_attrpair.php",
57
+ "spec/fixtures/group_by_day.php",
58
+ "spec/fixtures/group_by_day_sort.php",
59
+ "spec/fixtures/group_by_month.php",
60
+ "spec/fixtures/group_by_week.php",
61
+ "spec/fixtures/group_by_year.php",
62
+ "spec/fixtures/group_distinct.php",
63
+ "spec/fixtures/id_range.php",
64
+ "spec/fixtures/id_range64.php",
65
+ "spec/fixtures/index_weights.php",
66
+ "spec/fixtures/keywords.php",
67
+ "spec/fixtures/limits.php",
68
+ "spec/fixtures/limits_cutoff.php",
69
+ "spec/fixtures/limits_max.php",
70
+ "spec/fixtures/limits_max_cutoff.php",
71
+ "spec/fixtures/match_all.php",
72
+ "spec/fixtures/match_any.php",
73
+ "spec/fixtures/match_boolean.php",
74
+ "spec/fixtures/match_extended.php",
75
+ "spec/fixtures/match_extended2.php",
76
+ "spec/fixtures/match_fullscan.php",
77
+ "spec/fixtures/match_phrase.php",
78
+ "spec/fixtures/max_query_time.php",
79
+ "spec/fixtures/miltiple_queries.php",
80
+ "spec/fixtures/ranking_bm25.php",
81
+ "spec/fixtures/ranking_none.php",
82
+ "spec/fixtures/ranking_proximity_bm25.php",
83
+ "spec/fixtures/ranking_wordcount.php",
84
+ "spec/fixtures/retries.php",
85
+ "spec/fixtures/retries_delay.php",
86
+ "spec/fixtures/sort_attr_asc.php",
87
+ "spec/fixtures/sort_attr_desc.php",
88
+ "spec/fixtures/sort_expr.php",
89
+ "spec/fixtures/sort_extended.php",
90
+ "spec/fixtures/sort_relevance.php",
91
+ "spec/fixtures/sort_time_segments.php",
92
+ "spec/fixtures/sphinxapi.php",
93
+ "spec/fixtures/update_attributes.php",
94
+ "spec/fixtures/weights.php",
95
+ "spec/sphinx/sphinx.conf",
96
+ "spec/sphinx/sphinx_test.sql"
97
+ ]
98
+ s.homepage = %q{http://github.com/kpumuk/rlibsphinxclient}
99
+ s.rdoc_options = ["--charset=UTF-8"]
100
+ s.require_paths = ["lib"]
101
+ s.rubygems_version = %q{1.3.5}
102
+ s.summary = %q{A Ruby wrapper for pure C searchd client API library.}
103
+ s.test_files = [
104
+ "spec/client_response_spec.rb",
105
+ "spec/client_spec.rb"
106
+ ]
107
+
108
+ if s.respond_to? :specification_version then
109
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
110
+ s.specification_version = 3
111
+
112
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
113
+ else
114
+ end
115
+ else
116
+ end
117
+ end
@@ -0,0 +1,135 @@
1
+ require File.dirname(__FILE__) + '/../init'
2
+
3
+ describe 'client API library', :shared => true do
4
+ it 'should have all filters working' do
5
+ @sphinx.SetServer('localhost', 3312)
6
+ @sphinx.SetLimits(1, 100, 20, 30)
7
+ @sphinx.SetMaxQueryTime(5)
8
+ @sphinx.SetMatchMode(Sphinx::Client::SPH_MATCH_EXTENDED2)
9
+ @sphinx.SetRankingMode(Sphinx::Client::SPH_RANK_BM25)
10
+ @sphinx.SetSortMode(Sphinx::Client::SPH_SORT_RELEVANCE)
11
+ @sphinx.SetFieldWeights('group_id' => 10, 'rating' => 20)
12
+ @sphinx.SetIndexWeights('test1' => 20, 'test2' => 30)
13
+ @sphinx.SetIDRange(1, 100)
14
+ @sphinx.SetFilter('group_id', [1], true)
15
+ @sphinx.SetFilterRange('group_id', 1, 2, true)
16
+ @sphinx.SetFilterFloatRange('rating', 1, 3, true)
17
+ @sphinx.SetGroupBy('created_at', Sphinx::Client::SPH_GROUPBY_DAY)
18
+ @sphinx.SetGroupDistinct('group_id')
19
+ @sphinx.SetRetries(5, 10)
20
+ result = @sphinx.Query('wifi', 'test1')
21
+
22
+ result.should_not be_nil
23
+ end
24
+
25
+ it 'should parse response in Query method' do
26
+ result = @sphinx.Query('wifi', 'test1')
27
+ validate_results_wifi(result)
28
+ end
29
+
30
+ it 'should process 64-bit keys in Query method' do
31
+ result = @sphinx.Query('wifi', 'test2')
32
+ result['total_found'].should == 3
33
+ result['matches'].length.should == 3
34
+ result['matches'][0]['id'].should == 4294967298
35
+ result['matches'][1]['id'].should == 4294967299
36
+ result['matches'][2]['id'].should == 4294967297
37
+ end
38
+
39
+ it 'should parse batch-query responce in RunQueries method' do
40
+ @sphinx.AddQuery('wifi', 'test1')
41
+ @sphinx.AddQuery('gprs', 'test1')
42
+ results = @sphinx.RunQueries
43
+ results.should be_an(Array)
44
+ results.length.should == 2
45
+ validate_results_wifi(results[0])
46
+ end
47
+
48
+ it 'should parse response in BuildExcerpts method' do
49
+ result = @sphinx.BuildExcerpts(['what the world', 'London is the capital of Great Britain'], 'test1', 'the')
50
+ result.should == ['what <b>the</b> world', 'London is <b>the</b> capital of Great Britain']
51
+ end
52
+
53
+ it 'should parse response in BuildKeywords method' do
54
+ result = @sphinx.BuildKeywords('wifi gprs', 'test1', true)
55
+ result.should == [
56
+ { 'normalized' => 'wifi', 'tokenized' => 'wifi', 'hits' => 6, 'docs' => 3 },
57
+ { 'normalized' => 'gprs', 'tokenized' => 'gprs', 'hits' => 1, 'docs' => 1 }
58
+ ]
59
+ end
60
+
61
+ it 'should parse response in UpdateAttributes method' do
62
+ @sphinx.UpdateAttributes('test1', ['group_id'], { 2 => [1] }).should == 1
63
+ result = @sphinx.Query('wifi', 'test1')
64
+ result['matches'][0]['attrs']['group_id'].should == 1
65
+ @sphinx.UpdateAttributes('test1', ['group_id'], { 2 => [2] }).should == 1
66
+ result = @sphinx.Query('wifi', 'test1')
67
+ result['matches'][0]['attrs']['group_id'].should == 2
68
+ end
69
+
70
+ it 'should process errors in Query method' do
71
+ @sphinx.Query('wifi', 'fakeindex').should be_false
72
+ @sphinx.GetLastError.length.should_not == 0
73
+ end
74
+
75
+ it 'should process errors in RunQueries method' do
76
+ @sphinx.AddQuery('wifi', 'fakeindex')
77
+ r = @sphinx.RunQueries
78
+ r.should be_an(Array)
79
+ r[0]['error'].length.should_not == 0
80
+ end
81
+
82
+ def validate_results_wifi(result)
83
+ result['total_found'].should == 3
84
+ result['matches'].length.should == 3
85
+ result['time'].should_not be_nil
86
+ result['attrs'].should == {
87
+ 'group_id' => Sphinx::Client::SPH_ATTR_INTEGER,
88
+ 'created_at' => Sphinx::Client::SPH_ATTR_TIMESTAMP,
89
+ 'rating' => Sphinx::Client::SPH_ATTR_FLOAT,
90
+ 'tags' => Sphinx::Client::SPH_ATTR_MULTI | Sphinx::Client::SPH_ATTR_INTEGER
91
+ }
92
+ result['fields'].should == [ 'name', 'description' ]
93
+ result['total'].should == 3
94
+ result['matches'].should be_an(Array)
95
+
96
+ result['matches'][0]['id'].should == 2
97
+ result['matches'][0]['weight'].should == 2
98
+ result['matches'][0]['attrs']['group_id'].should == 2
99
+ result['matches'][0]['attrs']['created_at'].should == 1175658555
100
+ result['matches'][0]['attrs']['tags'].should == [5, 6, 7, 8]
101
+ ('%0.2f' % result['matches'][0]['attrs']['rating']).should == '54.85'
102
+
103
+ result['matches'][1]['id'].should == 3
104
+ result['matches'][1]['weight'].should == 2
105
+ result['matches'][1]['attrs']['group_id'].should == 1
106
+ result['matches'][1]['attrs']['created_at'].should == 1175658647
107
+ result['matches'][1]['attrs']['tags'].should == [1, 7, 9, 10]
108
+ ('%0.2f' % result['matches'][1]['attrs']['rating']).should == '16.25'
109
+
110
+ result['matches'][2]['id'].should == 1
111
+ result['matches'][2]['weight'].should == 1
112
+ result['matches'][2]['attrs']['group_id'].should == 1
113
+ result['matches'][2]['attrs']['created_at'].should == 1175658490
114
+ result['matches'][2]['attrs']['tags'].should == [1, 2, 3, 4]
115
+ ('%0.2f' % result['matches'][2]['attrs']['rating']).should == '13.32'
116
+
117
+ result['words'].should == { 'wifi' => { 'hits' => 6, 'docs' => 3 } }
118
+ end
119
+ end
120
+
121
+ # To execute these tests you need to execute sphinx_test.sql and configure sphinx using sphinx.conf
122
+ # (both files are placed under sphinx directory)
123
+ describe 'The Sphinx::Client connected to Sphinx' do
124
+ before(:each) { @sphinx = Sphinx::Client.new }
125
+ after (:each) { @sphinx.destroy }
126
+
127
+ it_should_behave_like 'client API library'
128
+ end
129
+
130
+ describe 'The Sphinx::FastClient connected to Sphinx' do
131
+ before(:each) { @sphinx = Sphinx::FastClient.new }
132
+ after (:each) { @sphinx.destroy }
133
+
134
+ it_should_behave_like 'client API library'
135
+ end