pixeltrix-thinking-sphinx 1.1.5 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +147 -0
- data/lib/thinking_sphinx/active_record/attribute_updates.rb +48 -0
- data/lib/thinking_sphinx/active_record/delta.rb +14 -1
- data/lib/thinking_sphinx/active_record/scopes.rb +37 -0
- data/lib/thinking_sphinx/active_record.rb +46 -12
- data/lib/thinking_sphinx/adapters/abstract_adapter.rb +9 -1
- data/lib/thinking_sphinx/adapters/mysql_adapter.rb +3 -2
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +12 -5
- data/lib/thinking_sphinx/association.rb +20 -0
- data/lib/thinking_sphinx/attribute.rb +187 -116
- data/lib/thinking_sphinx/class_facet.rb +15 -0
- data/lib/thinking_sphinx/configuration.rb +46 -14
- data/lib/thinking_sphinx/core/string.rb +3 -10
- data/lib/thinking_sphinx/deltas/datetime_delta.rb +3 -3
- data/lib/thinking_sphinx/deltas/default_delta.rb +9 -6
- data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +1 -1
- data/lib/thinking_sphinx/deltas/delayed_delta.rb +4 -2
- data/lib/thinking_sphinx/deltas.rb +14 -6
- data/lib/thinking_sphinx/deploy/capistrano.rb +98 -0
- data/lib/thinking_sphinx/excerpter.rb +22 -0
- data/lib/thinking_sphinx/facet.rb +68 -18
- data/lib/thinking_sphinx/facet_search.rb +134 -0
- data/lib/thinking_sphinx/field.rb +7 -97
- data/lib/thinking_sphinx/index/builder.rb +255 -201
- data/lib/thinking_sphinx/index.rb +28 -343
- data/lib/thinking_sphinx/property.rb +160 -0
- data/lib/thinking_sphinx/rails_additions.rb +7 -4
- data/lib/thinking_sphinx/search.rb +593 -587
- data/lib/thinking_sphinx/search_methods.rb +421 -0
- data/lib/thinking_sphinx/source/internal_properties.rb +46 -0
- data/lib/thinking_sphinx/source/sql.rb +128 -0
- data/lib/thinking_sphinx/source.rb +150 -0
- data/lib/thinking_sphinx/tasks.rb +45 -11
- data/lib/thinking_sphinx.rb +88 -14
- data/rails/init.rb +14 -0
- data/spec/{unit → lib}/thinking_sphinx/active_record/delta_spec.rb +7 -7
- data/spec/{unit → lib}/thinking_sphinx/active_record/has_many_association_spec.rb +0 -0
- data/spec/lib/thinking_sphinx/active_record/scopes_spec.rb +92 -0
- data/spec/{unit → lib}/thinking_sphinx/active_record_spec.rb +115 -42
- data/spec/{unit → lib}/thinking_sphinx/association_spec.rb +4 -5
- data/spec/lib/thinking_sphinx/attribute_spec.rb +465 -0
- data/spec/{unit → lib}/thinking_sphinx/configuration_spec.rb +118 -7
- data/spec/{unit → lib}/thinking_sphinx/core/string_spec.rb +0 -0
- data/spec/lib/thinking_sphinx/excerpter_spec.rb +49 -0
- data/spec/lib/thinking_sphinx/facet_search_spec.rb +176 -0
- data/spec/lib/thinking_sphinx/facet_spec.rb +302 -0
- data/spec/{unit → lib}/thinking_sphinx/field_spec.rb +26 -17
- data/spec/lib/thinking_sphinx/index/builder_spec.rb +355 -0
- data/spec/{unit → lib}/thinking_sphinx/index/faux_column_spec.rb +0 -0
- data/spec/{unit → lib}/thinking_sphinx/index_spec.rb +3 -12
- data/spec/lib/thinking_sphinx/rails_additions_spec.rb +191 -0
- data/spec/lib/thinking_sphinx/search_methods_spec.rb +152 -0
- data/spec/lib/thinking_sphinx/search_spec.rb +887 -0
- data/spec/lib/thinking_sphinx/source_spec.rb +217 -0
- data/spec/{unit → lib}/thinking_sphinx_spec.rb +30 -8
- data/tasks/distribution.rb +20 -1
- data/tasks/testing.rb +7 -15
- data/vendor/after_commit/init.rb +3 -0
- data/vendor/after_commit/lib/after_commit/active_record.rb +27 -4
- data/vendor/after_commit/lib/after_commit/connection_adapters.rb +1 -1
- data/vendor/after_commit/lib/after_commit.rb +4 -1
- data/vendor/riddle/lib/riddle/client/message.rb +4 -3
- data/vendor/riddle/lib/riddle/client.rb +3 -0
- data/vendor/riddle/lib/riddle/configuration/section.rb +8 -2
- data/vendor/riddle/lib/riddle/controller.rb +1 -1
- data/vendor/riddle/lib/riddle.rb +1 -1
- metadata +75 -39
- data/README +0 -107
- data/lib/thinking_sphinx/active_record/search.rb +0 -57
- data/lib/thinking_sphinx/collection.rb +0 -142
- data/lib/thinking_sphinx/facet_collection.rb +0 -44
- data/spec/unit/thinking_sphinx/active_record/search_spec.rb +0 -107
- data/spec/unit/thinking_sphinx/attribute_spec.rb +0 -212
- data/spec/unit/thinking_sphinx/collection_spec.rb +0 -14
- data/spec/unit/thinking_sphinx/index/builder_spec.rb +0 -5
- data/spec/unit/thinking_sphinx/search_spec.rb +0 -59
data/README.textile
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
h1. Thinking Sphinx
|
2
|
+
|
3
|
+
h2. Usage
|
4
|
+
|
5
|
+
First, if you haven't done so already, check out the main "usage":http://ts.freelancing-gods.com/usage.html page. Once you've done that, the next place to look for information is the specific method docs - ThinkingSphinx::Search and ThinkingSphinx::Index::Builder in particular.
|
6
|
+
|
7
|
+
Keep in mind that while Thinking Sphinx works for ActiveRecord with Merb, it doesn't yet support DataMapper (although that is planned).
|
8
|
+
|
9
|
+
h2. Contributing
|
10
|
+
|
11
|
+
Fork on GitHub and after you've committed tested patches, send a pull request.
|
12
|
+
|
13
|
+
To quickly see if your system is ready to run the thinking sphinx specs, run the contribute.rb script found in the project root directory. Use the following instructions to install any missing requirements.
|
14
|
+
|
15
|
+
To get the spec suite running, you will need to install the not-a-mock gem if you don't already have it:
|
16
|
+
|
17
|
+
git clone git://github.com/freelancing-god/not-a-mock.git
|
18
|
+
cd not-a-mock
|
19
|
+
rake gem
|
20
|
+
gem install pkg/not_a_mock-1.1.0.gem
|
21
|
+
|
22
|
+
Then install the ginger gem. The steps are the same, except that you might need to sudo the gem install:
|
23
|
+
|
24
|
+
git clone git://github.com/freelancing-god/ginger.git
|
25
|
+
cd ginger
|
26
|
+
rake gem
|
27
|
+
sudo gem install pkg/ginger-1.1.0.gem
|
28
|
+
|
29
|
+
Alternatively, install the ginger gem directly from the freelancing-god github repository
|
30
|
+
|
31
|
+
sudo gem sources -a http://gems.github.com
|
32
|
+
sudo gem install freelancing-god-ginger
|
33
|
+
|
34
|
+
Then set up your database:
|
35
|
+
|
36
|
+
cp spec/fixtures/database.yml.default spec/fixtures/database.yml
|
37
|
+
mysqladmin -u root create thinking_sphinx
|
38
|
+
|
39
|
+
This last step can be done automatically by the contribute.rb script if all dependencies are met.
|
40
|
+
|
41
|
+
Make sure you don't have another Sphinx daemon (searchd) running. If you do, quit it with "rake ts:stop"
|
42
|
+
in the app root.
|
43
|
+
|
44
|
+
You should now have a passing test suite from which to build your patch on.
|
45
|
+
|
46
|
+
rake spec
|
47
|
+
|
48
|
+
If you get the message "Failed to start searchd daemon", run the spec with sudo:
|
49
|
+
|
50
|
+
sudo rake spec
|
51
|
+
|
52
|
+
If you quit the spec suite before it's completed, you may be left with data in the test
|
53
|
+
database, causing the next run to have failures. Let that run complete and then try again.
|
54
|
+
|
55
|
+
h2. Contributors
|
56
|
+
|
57
|
+
Since I first released this library, there's been quite a few people who have submitted patches, to my immense gratitude. Others have suggested syntax changes and general improvements. So my thanks to the following people:
|
58
|
+
|
59
|
+
* Joost Hietbrink
|
60
|
+
* Jonathan Conway
|
61
|
+
* Gregory Mirzayantz
|
62
|
+
* Tung Nguyen
|
63
|
+
* Sean Cribbs
|
64
|
+
* Benoit Caccinolo
|
65
|
+
* John Barton
|
66
|
+
* Oliver Beddows
|
67
|
+
* Arthur Zapparoli
|
68
|
+
* Dusty Doris
|
69
|
+
* Marcus Crafter
|
70
|
+
* Patrick Lenz
|
71
|
+
* Björn Andreasson
|
72
|
+
* James Healy
|
73
|
+
* Jae-Jun Hwang
|
74
|
+
* Xavier Shay
|
75
|
+
* Jason Rust
|
76
|
+
* Gopal Patel
|
77
|
+
* Chris Heald
|
78
|
+
* Peter Vandenberk
|
79
|
+
* Josh French
|
80
|
+
* Andrew Bennett
|
81
|
+
* Jordan Fowler
|
82
|
+
* Seth Walker
|
83
|
+
* Joe Noon
|
84
|
+
* Wolfgang Postler
|
85
|
+
* Rick Olson
|
86
|
+
* Killian Murphy
|
87
|
+
* Morten Primdahl
|
88
|
+
* Ryan Bates
|
89
|
+
* David Eisinger
|
90
|
+
* Shay Arnett
|
91
|
+
* Minh Tran
|
92
|
+
* Jeremy Durham
|
93
|
+
* Piotr Sarnacki
|
94
|
+
* Matt Johnson
|
95
|
+
* Nicolas Blanco
|
96
|
+
* Max Lapshin
|
97
|
+
* Josh Natanson
|
98
|
+
* Philip Hallstrom
|
99
|
+
* Christian Rishøj
|
100
|
+
* Mike Flester
|
101
|
+
* Jim Remsik
|
102
|
+
* Kennon Ballou
|
103
|
+
* Henrik Nyh
|
104
|
+
* Emil Tin
|
105
|
+
* Doug Cole
|
106
|
+
* Ed Hickey
|
107
|
+
* Evan Weaver
|
108
|
+
* Thibaut Barrere
|
109
|
+
* Kristopher Chambers
|
110
|
+
* Dmitrij Smalko
|
111
|
+
* Aleksey Yeschenko
|
112
|
+
* Lachie Cox
|
113
|
+
* Lourens Naude
|
114
|
+
* Tom Davies
|
115
|
+
* Dan Pickett
|
116
|
+
* Alex Caudill
|
117
|
+
* Jim Benton
|
118
|
+
* John Aughey
|
119
|
+
* Keith Pitty
|
120
|
+
* Jeff Talbot
|
121
|
+
* Dana Contreras
|
122
|
+
* Menno van der Sman
|
123
|
+
* Bill Harding
|
124
|
+
* Isaac Feliu
|
125
|
+
* Andrei Bocan
|
126
|
+
* László Bácsi
|
127
|
+
* Peter Wagenet
|
128
|
+
* Max Lapshin
|
129
|
+
* Martin Emde
|
130
|
+
* David Wennergren
|
131
|
+
* Mark Lane
|
132
|
+
* Eric Lindvall
|
133
|
+
* Lawrence Pit
|
134
|
+
* Mike Bailey
|
135
|
+
* Bill Leeper
|
136
|
+
* Michael Reinsch
|
137
|
+
* Anderson Dias
|
138
|
+
* Jerome Riga
|
139
|
+
* Tien Dung
|
140
|
+
* Johannes Kaefer
|
141
|
+
* Paul Campbell
|
142
|
+
* Matthew Beale
|
143
|
+
* Tom Simnett
|
144
|
+
* Erik Ostrom
|
145
|
+
* Ole Riesenberg
|
146
|
+
* Josh Kalderimis
|
147
|
+
* J.D. Hollis
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module ThinkingSphinx
|
2
|
+
module ActiveRecord
|
3
|
+
module AttributeUpdates
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
after_commit :update_attribute_values
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def update_attribute_values
|
13
|
+
return unless ThinkingSphinx.updates_enabled? && ThinkingSphinx.sphinx_running?
|
14
|
+
|
15
|
+
config = ThinkingSphinx::Configuration.instance
|
16
|
+
client = Riddle::Client.new config.address, config.port
|
17
|
+
|
18
|
+
self.sphinx_indexes.each do |index|
|
19
|
+
attribute_pairs = attribute_values_for_index(index)
|
20
|
+
attribute_names = attribute_pairs.keys
|
21
|
+
attribute_values = attribute_names.collect { |key|
|
22
|
+
attribute_pairs[key]
|
23
|
+
}
|
24
|
+
|
25
|
+
client.update "#{index.name}_core", attribute_names, {
|
26
|
+
sphinx_document_id => attribute_values
|
27
|
+
} if in_core_index?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def updatable_attributes(index)
|
32
|
+
index.attributes.select { |attrib| attrib.updatable? }
|
33
|
+
end
|
34
|
+
|
35
|
+
def attribute_values_for_index(index)
|
36
|
+
updatable_attributes(index).inject({}) { |hash, attrib|
|
37
|
+
if attrib.type == :datetime
|
38
|
+
hash[attrib.unique_name.to_s] = attrib.live_value(self).to_time.to_i
|
39
|
+
else
|
40
|
+
hash[attrib.unique_name.to_s] = attrib.live_value self
|
41
|
+
end
|
42
|
+
|
43
|
+
hash
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -50,6 +50,10 @@ module ThinkingSphinx
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
+
def toggled_delta?
|
54
|
+
self.class.delta_object.toggled(self)
|
55
|
+
end
|
56
|
+
|
53
57
|
private
|
54
58
|
|
55
59
|
# Set the delta value for the model to be true.
|
@@ -65,7 +69,16 @@ module ThinkingSphinx
|
|
65
69
|
end
|
66
70
|
|
67
71
|
def should_toggle_delta?
|
68
|
-
|
72
|
+
self.new_record? || indexed_data_changed?
|
73
|
+
end
|
74
|
+
|
75
|
+
def indexed_data_changed?
|
76
|
+
sphinx_indexes.any? { |index|
|
77
|
+
index.fields.any? { |field| field.changed?(self) } ||
|
78
|
+
index.attributes.any? { |attrib|
|
79
|
+
attrib.public? && attrib.changed?(self) && !attrib.updatable?
|
80
|
+
}
|
81
|
+
}
|
69
82
|
end
|
70
83
|
end
|
71
84
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module ThinkingSphinx
|
2
|
+
module ActiveRecord
|
3
|
+
module Scopes
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
extend ThinkingSphinx::ActiveRecord::Scopes::ClassMethods
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def sphinx_scope(method, &block)
|
12
|
+
@sphinx_scopes ||= []
|
13
|
+
@sphinx_scopes << method
|
14
|
+
|
15
|
+
metaclass.instance_eval do
|
16
|
+
define_method(method) do |*args|
|
17
|
+
options = block.call(*args)
|
18
|
+
ThinkingSphinx::Search.new(options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def sphinx_scopes
|
24
|
+
@sphinx_scopes || []
|
25
|
+
end
|
26
|
+
|
27
|
+
def remove_sphinx_scopes
|
28
|
+
sphinx_scopes.each do |scope|
|
29
|
+
metaclass.send(:undef_method, scope)
|
30
|
+
end
|
31
|
+
|
32
|
+
sphinx_scopes.clear
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
|
+
require 'thinking_sphinx/active_record/attribute_updates'
|
1
2
|
require 'thinking_sphinx/active_record/delta'
|
2
|
-
require 'thinking_sphinx/active_record/search'
|
3
3
|
require 'thinking_sphinx/active_record/has_many_association'
|
4
|
+
require 'thinking_sphinx/active_record/scopes'
|
4
5
|
|
5
6
|
module ThinkingSphinx
|
6
7
|
# Core additions to ActiveRecord models - define_index for creating indexes
|
@@ -65,7 +66,7 @@ module ThinkingSphinx
|
|
65
66
|
return unless ThinkingSphinx.define_indexes?
|
66
67
|
|
67
68
|
self.sphinx_indexes ||= []
|
68
|
-
index = Index.
|
69
|
+
index = ThinkingSphinx::Index::Builder.generate(self, &block)
|
69
70
|
|
70
71
|
self.sphinx_indexes << index
|
71
72
|
unless ThinkingSphinx.indexed_models.include?(self.name)
|
@@ -79,7 +80,22 @@ module ThinkingSphinx
|
|
79
80
|
|
80
81
|
after_destroy :toggle_deleted
|
81
82
|
|
83
|
+
include ThinkingSphinx::SearchMethods
|
84
|
+
include ThinkingSphinx::ActiveRecord::AttributeUpdates
|
85
|
+
include ThinkingSphinx::ActiveRecord::Scopes
|
86
|
+
|
82
87
|
index
|
88
|
+
|
89
|
+
# We want to make sure that if the database doesn't exist, then Thinking
|
90
|
+
# Sphinx doesn't mind when running non-TS tasks (like db:create, db:drop
|
91
|
+
# and db:migrate). It's a bit hacky, but I can't think of a better way.
|
92
|
+
rescue StandardError => err
|
93
|
+
case err.class.name
|
94
|
+
when "Mysql::Error", "Java::JavaSql::SQLException", "ActiveRecord::StatementInvalid"
|
95
|
+
return
|
96
|
+
else
|
97
|
+
raise err
|
98
|
+
end
|
83
99
|
end
|
84
100
|
alias_method :sphinx_index, :define_index
|
85
101
|
|
@@ -126,12 +142,12 @@ module ThinkingSphinx
|
|
126
142
|
ThinkingSphinx::AbstractAdapter.detect(self)
|
127
143
|
end
|
128
144
|
|
129
|
-
private
|
130
|
-
|
131
145
|
def sphinx_name
|
132
146
|
self.name.underscore.tr(':/\\', '_')
|
133
147
|
end
|
134
148
|
|
149
|
+
private
|
150
|
+
|
135
151
|
def sphinx_delta?
|
136
152
|
self.sphinx_indexes.any? { |index| index.delta? }
|
137
153
|
end
|
@@ -148,7 +164,9 @@ module ThinkingSphinx
|
|
148
164
|
self.sphinx_indexes.select { |ts_index|
|
149
165
|
ts_index.model == self
|
150
166
|
}.each_with_index do |ts_index, i|
|
151
|
-
index.sources
|
167
|
+
index.sources += ts_index.sources.collect { |source|
|
168
|
+
source.to_riddle_for_core(offset, i)
|
169
|
+
}
|
152
170
|
end
|
153
171
|
|
154
172
|
index
|
@@ -160,7 +178,9 @@ module ThinkingSphinx
|
|
160
178
|
index.path = File.join(ThinkingSphinx::Configuration.instance.searchd_file_path, index.name)
|
161
179
|
|
162
180
|
self.sphinx_indexes.each_with_index do |ts_index, i|
|
163
|
-
index.sources
|
181
|
+
index.sources += ts_index.sources.collect { |source|
|
182
|
+
source.to_riddle_for_delta(offset, i)
|
183
|
+
} if ts_index.delta?
|
164
184
|
end
|
165
185
|
|
166
186
|
index
|
@@ -197,7 +217,6 @@ module ThinkingSphinx
|
|
197
217
|
end
|
198
218
|
|
199
219
|
base.send(:include, ThinkingSphinx::ActiveRecord::Delta)
|
200
|
-
base.send(:include, ThinkingSphinx::ActiveRecord::Search)
|
201
220
|
|
202
221
|
::ActiveRecord::Associations::HasManyAssociation.send(
|
203
222
|
:include, ThinkingSphinx::ActiveRecord::HasManyAssociation
|
@@ -207,11 +226,20 @@ module ThinkingSphinx
|
|
207
226
|
)
|
208
227
|
end
|
209
228
|
|
229
|
+
def in_index?(suffix)
|
230
|
+
self.class.search_for_id self.sphinx_document_id, sphinx_index_name(suffix)
|
231
|
+
end
|
232
|
+
|
210
233
|
def in_core_index?
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
234
|
+
in_index? "core"
|
235
|
+
end
|
236
|
+
|
237
|
+
def in_delta_index?
|
238
|
+
in_index? "delta"
|
239
|
+
end
|
240
|
+
|
241
|
+
def in_both_indexes?
|
242
|
+
in_core_index? && in_delta_index?
|
215
243
|
end
|
216
244
|
|
217
245
|
def toggle_deleted
|
@@ -232,7 +260,7 @@ module ThinkingSphinx
|
|
232
260
|
{self.sphinx_document_id => 1}
|
233
261
|
) if ThinkingSphinx.deltas_enabled? &&
|
234
262
|
self.class.sphinx_indexes.any? { |index| index.delta? } &&
|
235
|
-
self.
|
263
|
+
self.toggled_delta?
|
236
264
|
rescue ::ThinkingSphinx::ConnectionError
|
237
265
|
# nothing
|
238
266
|
end
|
@@ -241,5 +269,11 @@ module ThinkingSphinx
|
|
241
269
|
(self.id * ThinkingSphinx.indexed_models.size) +
|
242
270
|
ThinkingSphinx.indexed_models.index(self.class.source_of_sphinx_index.name)
|
243
271
|
end
|
272
|
+
|
273
|
+
private
|
274
|
+
|
275
|
+
def sphinx_index_name(suffix)
|
276
|
+
"#{self.class.source_of_sphinx_index.name.underscore.tr(':/\\', '_')}_#{suffix}"
|
277
|
+
end
|
244
278
|
end
|
245
279
|
end
|
@@ -16,8 +16,16 @@ module ThinkingSphinx
|
|
16
16
|
ThinkingSphinx::MysqlAdapter.new model
|
17
17
|
when "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter"
|
18
18
|
ThinkingSphinx::PostgreSQLAdapter.new model
|
19
|
+
when "ActiveRecord::ConnectionAdapters::JdbcAdapter"
|
20
|
+
if model.connection.config[:adapter] == "jdbcmysql"
|
21
|
+
ThinkingSphinx::MysqlAdapter.new model
|
22
|
+
elsif model.connection.config[:adapter] == "jdbcpostgresql"
|
23
|
+
ThinkingSphinx::PostgreSQLAdapter.new model
|
24
|
+
else
|
25
|
+
raise "Invalid Database Adapter: Sphinx only supports MySQL and PostgreSQL"
|
26
|
+
end
|
19
27
|
else
|
20
|
-
raise "Invalid Database Adapter: Sphinx only supports MySQL and PostgreSQL"
|
28
|
+
raise "Invalid Database Adapter: Sphinx only supports MySQL and PostgreSQL, not #{model.connection.class.name}"
|
21
29
|
end
|
22
30
|
end
|
23
31
|
|
@@ -13,7 +13,7 @@ module ThinkingSphinx
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def group_concatenate(clause, separator = ' ')
|
16
|
-
"GROUP_CONCAT(#{clause} SEPARATOR '#{separator}')"
|
16
|
+
"GROUP_CONCAT(DISTINCT #{clause} SEPARATOR '#{separator}')"
|
17
17
|
end
|
18
18
|
|
19
19
|
def cast_to_string(clause)
|
@@ -38,7 +38,8 @@ module ThinkingSphinx
|
|
38
38
|
value ? 1 : 0
|
39
39
|
end
|
40
40
|
|
41
|
-
def crc(clause)
|
41
|
+
def crc(clause, blank_to_null = false)
|
42
|
+
clause = "NULLIF(#{clause},'')" if blank_to_null
|
42
43
|
"CRC32(#{clause})"
|
43
44
|
end
|
44
45
|
|
@@ -11,7 +11,12 @@ module ThinkingSphinx
|
|
11
11
|
|
12
12
|
def concatenate(clause, separator = ' ')
|
13
13
|
clause.split(', ').collect { |field|
|
14
|
-
|
14
|
+
case field
|
15
|
+
when /COALESCE/, "'')"
|
16
|
+
field
|
17
|
+
else
|
18
|
+
"COALESCE(CAST(#{field} as varchar), '')"
|
19
|
+
end
|
15
20
|
}.join(" || '#{separator}' || ")
|
16
21
|
end
|
17
22
|
|
@@ -32,7 +37,8 @@ module ThinkingSphinx
|
|
32
37
|
end
|
33
38
|
|
34
39
|
def convert_nulls(clause, default = '')
|
35
|
-
default = "'#{default}'"
|
40
|
+
default = "'#{default}'" if default.is_a?(String)
|
41
|
+
default = 'NULL' if default.nil?
|
36
42
|
|
37
43
|
"COALESCE(#{clause}, #{default})"
|
38
44
|
end
|
@@ -41,7 +47,8 @@ module ThinkingSphinx
|
|
41
47
|
value ? 'TRUE' : 'FALSE'
|
42
48
|
end
|
43
49
|
|
44
|
-
def crc(clause)
|
50
|
+
def crc(clause, blank_to_null = false)
|
51
|
+
clause = "NULLIF(#{clause},'')" if blank_to_null
|
45
52
|
"crc32(#{clause})"
|
46
53
|
end
|
47
54
|
|
@@ -69,7 +76,7 @@ module ThinkingSphinx
|
|
69
76
|
end
|
70
77
|
|
71
78
|
def create_array_accum_function
|
72
|
-
if connection.raw_connection.server_version > 80200
|
79
|
+
if connection.raw_connection.respond_to?(:server_version) && connection.raw_connection.server_version > 80200
|
73
80
|
execute <<-SQL
|
74
81
|
CREATE AGGREGATE array_accum (anyelement)
|
75
82
|
(
|
@@ -126,4 +133,4 @@ module ThinkingSphinx
|
|
126
133
|
execute function, true
|
127
134
|
end
|
128
135
|
end
|
129
|
-
end
|
136
|
+
end
|
@@ -99,6 +99,26 @@ module ThinkingSphinx
|
|
99
99
|
@reflection.klass.column_names.include?(column.to_s)
|
100
100
|
end
|
101
101
|
|
102
|
+
def primary_key_from_reflection
|
103
|
+
if @reflection.options[:through]
|
104
|
+
@reflection.source_reflection.options[:foreign_key] ||
|
105
|
+
@reflection.source_reflection.primary_key_name
|
106
|
+
elsif @reflection.macro == :has_and_belongs_to_many
|
107
|
+
@reflection.association_foreign_key
|
108
|
+
else
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def table
|
114
|
+
if @reflection.options[:through] ||
|
115
|
+
@reflection.macro == :has_and_belongs_to_many
|
116
|
+
@join.aliased_join_table_name
|
117
|
+
else
|
118
|
+
@join.aliased_table_name
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
102
122
|
private
|
103
123
|
|
104
124
|
# Returns all the objects that could be currently instantiated from a
|