thinking-sphinx 1.4.6 → 1.4.7

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 (39) hide show
  1. data/README.textile +6 -1
  2. data/features/searching_by_model.feature +24 -30
  3. data/features/thinking_sphinx/db/.gitignore +1 -0
  4. data/features/thinking_sphinx/db/fixtures/post_keywords.txt +1 -0
  5. data/lib/cucumber/thinking_sphinx/internal_world.rb +26 -26
  6. data/lib/thinking_sphinx.rb +17 -26
  7. data/lib/thinking_sphinx/active_record.rb +69 -74
  8. data/lib/thinking_sphinx/active_record/attribute_updates.rb +11 -10
  9. data/lib/thinking_sphinx/active_record/has_many_association.rb +2 -1
  10. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +11 -11
  11. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +34 -20
  12. data/lib/thinking_sphinx/association.rb +12 -7
  13. data/lib/thinking_sphinx/attribute.rb +64 -61
  14. data/lib/thinking_sphinx/configuration.rb +32 -36
  15. data/lib/thinking_sphinx/context.rb +3 -2
  16. data/lib/thinking_sphinx/deploy/capistrano.rb +7 -9
  17. data/lib/thinking_sphinx/search.rb +201 -178
  18. data/lib/thinking_sphinx/source/sql.rb +1 -1
  19. data/lib/thinking_sphinx/tasks.rb +21 -19
  20. data/lib/thinking_sphinx/version.rb +3 -0
  21. data/spec/fixtures/data.sql +32 -0
  22. data/spec/fixtures/database.yml.default +3 -0
  23. data/spec/fixtures/models.rb +161 -0
  24. data/spec/fixtures/structure.sql +146 -0
  25. data/spec/spec_helper.rb +57 -0
  26. data/spec/sphinx_helper.rb +61 -0
  27. data/spec/thinking_sphinx/active_record/delta_spec.rb +24 -24
  28. data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +22 -0
  29. data/spec/thinking_sphinx/active_record/scopes_spec.rb +25 -25
  30. data/spec/thinking_sphinx/active_record_spec.rb +110 -109
  31. data/spec/thinking_sphinx/adapters/abstract_adapter_spec.rb +38 -38
  32. data/spec/thinking_sphinx/association_spec.rb +20 -2
  33. data/spec/thinking_sphinx/context_spec.rb +61 -64
  34. data/spec/thinking_sphinx/search_spec.rb +7 -0
  35. data/spec/thinking_sphinx_spec.rb +47 -46
  36. metadata +50 -98
  37. data/VERSION +0 -1
  38. data/tasks/distribution.rb +0 -34
  39. data/tasks/testing.rb +0 -80
@@ -122,7 +122,6 @@ Since I first released this library, there's been quite a few people who have su
122
122
  * Andrei Bocan
123
123
  * László Bácsi
124
124
  * Peter Wagenet
125
- * Max Lapshin
126
125
  * Martin Emde
127
126
  * David Wennergren
128
127
  * Mark Lane
@@ -192,3 +191,9 @@ Since I first released this library, there's been quite a few people who have su
192
191
  * Ryan Mohr
193
192
  * Alex Chee
194
193
  * Bruno Santschi
194
+ * Lars Weiler
195
+ * Andrey Deryabin
196
+ * Andrew White
197
+ * Rémi Prévost
198
+ * Justin Tanner
199
+ * Josh Goebel
@@ -2,19 +2,19 @@ Feature: Searching on a single model
2
2
  In order to use Thinking Sphinx's core functionality
3
3
  A developer
4
4
  Should be able to search on a single model
5
-
5
+
6
6
  Scenario: Searching using a basic query
7
7
  Given Sphinx is running
8
8
  And I am searching on people
9
9
  When I search for James
10
10
  Then I should get 3 results
11
-
11
+
12
12
  Scenario: Searching on a specific field
13
13
  Given Sphinx is running
14
14
  And I am searching on people
15
15
  When I search for James on first_name
16
16
  Then I should get 2 results
17
-
17
+
18
18
  Scenario: Searching on multiple fields
19
19
  Given Sphinx is running
20
20
  And I am searching on people
@@ -25,32 +25,32 @@ Feature: Searching on a single model
25
25
  Scenario: Searching on association content
26
26
  Given Sphinx is running
27
27
  And I am searching on posts
28
-
28
+
29
29
  When I search for "Waffles"
30
30
  Then I should get 1 result
31
31
 
32
32
  When I search for "Turtle"
33
33
  Then I should get 1 result
34
-
34
+
35
35
  Scenario: Searching with a filter
36
36
  Given Sphinx is running
37
37
  And I am searching on alphas
38
38
  When I filter by 1 on value
39
39
  Then I should get 1 result
40
-
40
+
41
41
  Scenario: Searching with multiple filters
42
42
  Given Sphinx is running
43
43
  And I am searching on boxes
44
44
  When I filter by 2 on width
45
45
  And I filter by 2 on length
46
46
  Then I should get 1 result
47
-
47
+
48
48
  Scenario: Searching with a ranged time filter
49
49
  Given Sphinx is running
50
50
  And I am searching on people
51
51
  When I filter by birthday between 1975 and 1976
52
52
  Then I should get 16 results
53
-
53
+
54
54
  Scenario: Searching to filter multiple values on an MVA
55
55
  Given Sphinx is running
56
56
  And I am searching on boxes
@@ -59,31 +59,25 @@ Feature: Searching on a single model
59
59
  When I clear existing filters
60
60
  And I filter by both 11 and 12 on dimensions
61
61
  Then I should get 1 result
62
-
62
+
63
63
  Scenario: Filtering on timestamp MVAs
64
64
  Given Sphinx is running
65
65
  And I am searching on posts
66
66
  When I filter by 2001-01-01 on comments_created_at
67
67
  Then I should get 1 result
68
-
69
- Scenario: Filtering on a wordcount attribute
70
- Given Sphinx is running
71
- And I am searching on developers
72
- When I filter between 0 and 1 on state_wordcount
73
- Then I should get 5 results
74
-
68
+
75
69
  Scenario: Searching by NULL/0 values in MVAs
76
70
  Given Sphinx is running
77
71
  And I am searching on boxes
78
72
  When I filter by 0 on dimensions
79
73
  Then I should get 1 result
80
-
74
+
81
75
  Given Sphinx is running
82
76
  And I am searching on developers
83
77
  When I clear existing filters
84
78
  And I filter by 0 on tag_ids
85
79
  Then I should get 1 result
86
-
80
+
87
81
  Scenario: Searching on a MVA configured as ranged_query
88
82
  Given Sphinx is running
89
83
  And I am searching on posts
@@ -95,59 +89,59 @@ Feature: Searching on a single model
95
89
  When I clear existing filters
96
90
  And I filter by 10 on comment_ids
97
91
  Then I should get 0 results
98
-
92
+
99
93
  Scenario: Searching with ordering by attribute
100
94
  Given Sphinx is running
101
95
  And I am searching on alphas
102
96
  When I order by value
103
97
  Then I should get 10 results
104
98
  And the value of each result should indicate order
105
-
99
+
106
100
  Scenario: Intepreting Sphinx Internal Identifiers
107
101
  Given Sphinx is running
108
102
  And I am searching on people
109
103
  Then I should get 20 results
110
104
  And each result id should match the corresponding sphinx internal id
111
-
105
+
112
106
  Scenario: Retrieving weightings
113
107
  Given Sphinx is running
114
108
  And I am searching on people
115
109
  When I search for "Ellie Ford"
116
110
  And I set match mode to any
117
111
  Then I can iterate by result and weighting
118
-
112
+
119
113
  Scenario: Retrieving group counts
120
114
  Given Sphinx is running
121
115
  And I am searching on people
122
116
  When I group results by the birthday attribute
123
117
  Then I can iterate by result and count
124
-
118
+
125
119
  Scenario: Retrieving group values
126
120
  Given Sphinx is running
127
121
  And I am searching on people
128
122
  When I group results by the birthday attribute
129
123
  Then I can iterate by result and group
130
-
124
+
131
125
  Scenario: Retrieving both group values and counts
132
126
  Given Sphinx is running
133
127
  And I am searching on people
134
128
  When I group results by the birthday attribute
135
129
  Then I can iterate by result and group and count
136
-
130
+
137
131
  Scenario: Searching for ids
138
132
  Given Sphinx is running
139
133
  And I am searching on people
140
134
  When I search for Ellie
141
135
  And I am searching for ids
142
136
  Then I should have an array of integers
143
-
137
+
144
138
  Scenario: Search results should match Sphinx's order
145
139
  Given Sphinx is running
146
140
  And I am searching on people
147
141
  When I search for Ellie
148
142
  And I order by "sphinx_internal_id DESC"
149
143
  Then searching for ids should match the record ids of the normal search results
150
-
144
+
151
145
  Scenario: Retrieving total result count when total is less than a page
152
146
  Given Sphinx is running
153
147
  And I am searching on people
@@ -160,7 +154,7 @@ Feature: Searching on a single model
160
154
  And I am searching on people
161
155
  When I am retrieving the result count
162
156
  Then I should get a value of 1000
163
-
157
+
164
158
  Scenario: Searching with Unicode Characters
165
159
  Given Sphinx is running
166
160
  And I am searching on people
@@ -172,10 +166,10 @@ Feature: Searching on a single model
172
166
  And I am searching on posts
173
167
  When I search for "Shakespeare"
174
168
  Then I should get 1 result
175
-
169
+
176
170
  Scenario: Searching on content from file field
177
171
  Given Sphinx is running
178
172
  And I am searching on posts
179
173
  When I search for "foo bar baz"
180
174
  Then I should get 1 result
181
-
175
+
@@ -0,0 +1 @@
1
+ database.yml
@@ -7,7 +7,7 @@ module Cucumber
7
7
  :models_directory, :fixtures_directory, :database_file
8
8
  attr_accessor :adapter, :database, :username,
9
9
  :password, :host
10
-
10
+
11
11
  def initialize
12
12
  pwd = Dir.pwd
13
13
  @temporary_directory = "#{pwd}/tmp"
@@ -15,55 +15,55 @@ module Cucumber
15
15
  @models_directory = "#{pwd}/features/thinking_sphinx/models"
16
16
  @fixtures_directory = "#{pwd}/features/thinking_sphinx/db/fixtures"
17
17
  @database_file = "#{pwd}/features/thinking_sphinx/database.yml"
18
-
19
- @adapter = ENV['DATABASE'] || 'mysql'
18
+
19
+ @adapter = (ENV['DATABASE'] || 'mysql').gsub /^mysql$/, 'mysql2'
20
20
  @database = 'thinking_sphinx'
21
- @username = 'thinking_sphinx'
21
+ @username = @adapter[/mysql/] ? 'root' : 'postgres'
22
22
  # @password = 'thinking_sphinx'
23
23
  @host = 'localhost'
24
24
  end
25
-
25
+
26
26
  def setup
27
27
  make_temporary_directory
28
-
28
+
29
29
  configure_cleanup
30
30
  configure_thinking_sphinx
31
31
  configure_active_record
32
-
32
+
33
33
  prepare_data
34
34
  setup_sphinx
35
-
35
+
36
36
  self
37
37
  end
38
-
38
+
39
39
  def configure_database
40
40
  ActiveRecord::Base.establish_connection database_settings
41
41
  self
42
42
  end
43
-
43
+
44
44
  private
45
-
45
+
46
46
  def config
47
47
  @config ||= ::ThinkingSphinx::Configuration.instance
48
48
  end
49
-
49
+
50
50
  def make_temporary_directory
51
51
  FileUtils.mkdir_p temporary_directory
52
52
  Dir["#{temporary_directory}/*"].each do |file|
53
53
  FileUtils.rm_rf file
54
54
  end
55
55
  end
56
-
56
+
57
57
  def configure_thinking_sphinx
58
58
  config.config_file = "#{temporary_directory}/sphinx.conf"
59
59
  config.searchd_log_file = "#{temporary_directory}/searchd.log"
60
60
  config.query_log_file = "#{temporary_directory}/searchd.query.log"
61
61
  config.pid_file = "#{temporary_directory}/searchd.pid"
62
62
  config.searchd_file_path = "#{temporary_directory}/indexes/"
63
-
63
+
64
64
  ::ThinkingSphinx.suppress_delta_output = true
65
65
  end
66
-
66
+
67
67
  def configure_cleanup
68
68
  Kernel.at_exit do
69
69
  ::ThinkingSphinx::Configuration.instance.controller.stop
@@ -71,13 +71,13 @@ module Cucumber
71
71
  ActiveRecord::Base.logger.close
72
72
  end
73
73
  end
74
-
74
+
75
75
  def yaml_database_settings
76
76
  return {} unless File.exist?(@database_file)
77
-
77
+
78
78
  YAML.load open(@database_file)
79
79
  end
80
-
80
+
81
81
  def database_settings
82
82
  {
83
83
  'adapter' => @adapter,
@@ -87,37 +87,37 @@ module Cucumber
87
87
  'host' => @host
88
88
  }.merge yaml_database_settings
89
89
  end
90
-
90
+
91
91
  def configure_active_record
92
92
  ActiveRecord::Base.logger = Logger.new(
93
93
  open("#{temporary_directory}/active_record.log", "a")
94
94
  )
95
-
95
+
96
96
  ActiveRecord::Base.connection.class.send(
97
97
  :include, Cucumber::ThinkingSphinx::SqlLogger
98
98
  )
99
99
  end
100
-
100
+
101
101
  def prepare_data
102
102
  ::ThinkingSphinx.deltas_enabled = false
103
-
103
+
104
104
  load_files migrations_directory
105
105
  load_files models_directory
106
106
  load_files fixtures_directory
107
-
107
+
108
108
  ::ThinkingSphinx.deltas_enabled = true
109
109
  end
110
-
110
+
111
111
  def load_files(path)
112
112
  files = Dir["#{path}/*.rb"].sort!
113
113
  files.each do |file|
114
114
  require file.gsub(/\.rb$/, '')
115
115
  end
116
116
  end
117
-
117
+
118
118
  def setup_sphinx
119
119
  FileUtils.mkdir_p config.searchd_file_path
120
-
120
+
121
121
  config.build
122
122
  config.controller.index
123
123
  config.controller.start
@@ -38,7 +38,7 @@ Merb::Plugins.add_rakefiles(
38
38
 
39
39
  module ThinkingSphinx
40
40
  mattr_accessor :database_adapter
41
-
41
+
42
42
  # A ConnectionError will get thrown when a connection to Sphinx can't be
43
43
  # made.
44
44
  class ConnectionError < StandardError
@@ -52,7 +52,7 @@ module ThinkingSphinx
52
52
  self.ids = ids
53
53
  end
54
54
  end
55
-
55
+
56
56
  # A SphinxError occurs when Sphinx responds with an error due to problematic
57
57
  # queries or indexes.
58
58
  class SphinxError < RuntimeError
@@ -62,17 +62,7 @@ module ThinkingSphinx
62
62
  self.results = results
63
63
  end
64
64
  end
65
-
66
- # The current version of Thinking Sphinx.
67
- #
68
- # @return [String] The version number as a string
69
- #
70
- def self.version
71
- open(File.join(File.dirname(__FILE__), '../VERSION')) { |f|
72
- f.read.strip
73
- }
74
- end
75
-
65
+
76
66
  # The collection of indexed models. Keep in mind that Rails lazily loads
77
67
  # its classes, so this may not actually be populated with _all_ the models
78
68
  # that have Sphinx indexes.
@@ -84,11 +74,11 @@ module ThinkingSphinx
84
74
  @@suppress_delta_output = false
85
75
  @@remote_sphinx = false
86
76
  @@use_group_by_shortcut = nil
87
-
77
+
88
78
  def self.mutex
89
79
  @@sphinx_mutex
90
80
  end
91
-
81
+
92
82
  def self.context
93
83
  if @@context.nil?
94
84
  mutex.synchronize do
@@ -98,10 +88,10 @@ module ThinkingSphinx
98
88
  end
99
89
  end
100
90
  end
101
-
91
+
102
92
  @@context
103
93
  end
104
-
94
+
105
95
  def self.reset_context!(context = nil)
106
96
  mutex.synchronize do
107
97
  @@context = context
@@ -127,7 +117,7 @@ module ThinkingSphinx
127
117
  @@define_indexes = value
128
118
  end
129
119
  end
130
-
120
+
131
121
  # Check if delta indexing is enabled/disabled.
132
122
  #
133
123
  def self.deltas_enabled?
@@ -140,10 +130,10 @@ module ThinkingSphinx
140
130
  end
141
131
  end
142
132
  end
143
-
133
+
144
134
  @@deltas_enabled && !deltas_suspended?
145
135
  end
146
-
136
+
147
137
  # Enable/disable delta indexing.
148
138
  #
149
139
  # ThinkingSphinx.deltas_enabled = false
@@ -160,7 +150,7 @@ module ThinkingSphinx
160
150
  if Thread.current[:thinking_sphinx_deltas_suspended].nil?
161
151
  Thread.current[:thinking_sphinx_deltas_suspended] = false
162
152
  end
163
-
153
+
164
154
  Thread.current[:thinking_sphinx_deltas_suspended]
165
155
  end
166
156
 
@@ -185,7 +175,7 @@ module ThinkingSphinx
185
175
  end
186
176
  end
187
177
  end
188
-
178
+
189
179
  @@updates_enabled
190
180
  end
191
181
 
@@ -208,7 +198,7 @@ module ThinkingSphinx
208
198
  @@suppress_delta_output = value
209
199
  end
210
200
  end
211
-
201
+
212
202
  # Checks to see if MySQL will allow simplistic GROUP BY statements. If not,
213
203
  # or if not using MySQL, this will return false.
214
204
  #
@@ -226,10 +216,10 @@ module ThinkingSphinx
226
216
  end
227
217
  end
228
218
  end
229
-
219
+
230
220
  @@use_group_by_shortcut
231
221
  end
232
-
222
+
233
223
  def self.reset_use_group_by_shortcut
234
224
  mutex.synchronize do
235
225
  @@use_group_by_shortcut = nil
@@ -298,11 +288,12 @@ module ThinkingSphinx
298
288
 
299
289
  def self.mysql?
300
290
  ::ActiveRecord::Base.connection.class.name.demodulize == "MysqlAdapter" ||
291
+ ::ActiveRecord::Base.connection.class.name.demodulize == "Mysql2Adapter" ||
301
292
  ::ActiveRecord::Base.connection.class.name.demodulize == "MysqlplusAdapter" || (
302
293
  jruby? && ::ActiveRecord::Base.connection.config[:adapter] == "jdbcmysql"
303
294
  )
304
295
  end
305
-
296
+
306
297
  extend ThinkingSphinx::SearchMethods::ClassMethods
307
298
  end
308
299