thinking-sphinx 3.0.0 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +6 -3
- data/HISTORY +18 -0
- data/README.textile +31 -8
- data/gemfiles/rails_3_1.gemfile +2 -2
- data/gemfiles/rails_3_2.gemfile +2 -2
- data/lib/thinking/sphinx.rb +1 -0
- data/lib/thinking_sphinx.rb +1 -0
- data/lib/thinking_sphinx/active_record.rb +2 -0
- data/lib/thinking_sphinx/active_record/association.rb +8 -0
- data/lib/thinking_sphinx/active_record/associations.rb +25 -5
- data/lib/thinking_sphinx/active_record/callbacks/delta_callbacks.rb +1 -5
- data/lib/thinking_sphinx/active_record/column.rb +12 -0
- data/lib/thinking_sphinx/active_record/database_adapters.rb +7 -0
- data/lib/thinking_sphinx/active_record/filtered_reflection.rb +49 -0
- data/lib/thinking_sphinx/active_record/interpreter.rb +6 -0
- data/lib/thinking_sphinx/active_record/polymorpher.rb +50 -0
- data/lib/thinking_sphinx/active_record/property.rb +6 -0
- data/lib/thinking_sphinx/active_record/property_query.rb +1 -1
- data/lib/thinking_sphinx/active_record/property_sql_presenter.rb +7 -1
- data/lib/thinking_sphinx/active_record/sql_builder.rb +7 -2
- data/lib/thinking_sphinx/active_record/sql_source.rb +5 -1
- data/lib/thinking_sphinx/capistrano.rb +64 -0
- data/lib/thinking_sphinx/configuration.rb +10 -1
- data/lib/thinking_sphinx/connection.rb +20 -0
- data/lib/thinking_sphinx/errors.rb +24 -0
- data/lib/thinking_sphinx/middlewares/sphinxql.rb +4 -1
- data/lib/thinking_sphinx/real_time/transcriber.rb +1 -1
- data/lib/thinking_sphinx/search/batch_inquirer.rb +3 -1
- data/lib/thinking_sphinx/search/glaze.rb +3 -3
- data/spec/acceptance/index_options_spec.rb +5 -0
- data/spec/acceptance/searching_on_fields_spec.rb +1 -0
- data/spec/acceptance/specifying_sql_spec.rb +107 -0
- data/spec/acceptance/sql_deltas_spec.rb +9 -0
- data/spec/acceptance/support/sphinx_controller.rb +1 -0
- data/spec/internal/app/models/event.rb +3 -0
- data/spec/internal/app/models/hardcover.rb +3 -0
- data/spec/internal/db/schema.rb +7 -1
- data/spec/thinking_sphinx/active_record/associations_spec.rb +2 -1
- data/spec/thinking_sphinx/active_record/callbacks/delta_callbacks_spec.rb +3 -3
- data/spec/thinking_sphinx/active_record/column_spec.rb +23 -0
- data/spec/thinking_sphinx/active_record/database_adapters_spec.rb +18 -0
- data/spec/thinking_sphinx/active_record/filtered_reflection_spec.rb +141 -0
- data/spec/thinking_sphinx/active_record/polymorpher_spec.rb +65 -0
- data/spec/thinking_sphinx/active_record/property_sql_presenter_spec.rb +28 -4
- data/spec/thinking_sphinx/active_record/sql_builder_spec.rb +11 -1
- data/spec/thinking_sphinx/configuration_spec.rb +24 -0
- data/spec/thinking_sphinx/connection_spec.rb +82 -0
- data/spec/thinking_sphinx/errors_spec.rb +36 -0
- data/spec/thinking_sphinx/middlewares/sphinxql_spec.rb +25 -0
- data/spec/thinking_sphinx/search/glaze_spec.rb +3 -0
- data/thinking-sphinx.gemspec +1 -1
- metadata +25 -3
data/.travis.yml
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
rvm:
|
2
2
|
- 1.9.2
|
3
3
|
- 1.9.3
|
4
|
-
before_install:
|
4
|
+
before_install:
|
5
|
+
- gem update --system
|
6
|
+
- curl -O http://fs-packages.s3.amazonaws.com/fs-sphinx-2.0.6_i386_12.04.deb
|
7
|
+
- sudo dpkg -i fs-sphinx-2.0.6_i386_12.04.deb
|
5
8
|
before_script:
|
6
9
|
- "mysql -e 'create database thinking_sphinx;' > /dev/null"
|
7
10
|
- "psql -c 'create database thinking_sphinx;' -U postgres >/dev/null"
|
8
11
|
env:
|
9
|
-
- DATABASE=mysql2
|
10
|
-
- DATABASE=postgresql
|
12
|
+
- DATABASE=mysql2 SPHINX_BIN=/usr/local/sphinx-2.0.6/bin/ SPHINX_VERSION=2.0.6
|
13
|
+
- DATABASE=postgresql SPHINX_BIN=/usr/local/sphinx-2.0.6/bin/ SPHINX_VERSION=2.0.6
|
11
14
|
gemfile:
|
12
15
|
- gemfiles/rails_3_1.gemfile
|
13
16
|
- gemfiles/rails_3_2.gemfile
|
data/HISTORY
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
2013-02-04: 3.0.1
|
2
|
+
* [FEATURE] Provide Capistrano deployment tasks (David Celis).
|
3
|
+
* [FEATURE] Allow specifying of Sphinx version. Is only useful for Flying Sphinx purposes at this point - has no impact on Riddle or Sphinx.
|
4
|
+
* [FEATURE] Support new JDBC configuration style (when JDBC can be used) (Kyle Stevens).
|
5
|
+
* [FIX] Referring to associations via polymorphic associations in an index definition now works.
|
6
|
+
* [FEATURE] Mysql2::Errors are wrapped as ThinkingSphinx::SphinxErrors, with subclasses of SyntaxError and ParseError used appropriately. Syntax and parse errors do not prompt a retry on a new connection.
|
7
|
+
* [CHANGE] Use connection pool for search queries. If a query fails, it will be retried on a new connection before raising if necessary.
|
8
|
+
* [CHANGE] Glaze always passes methods through to the underlying ActiveRecord::Base object if they don't exist on any of the panes.
|
9
|
+
* [FIX] Don't override foreign keys for polymorphic association replacements.
|
10
|
+
* [FIX] Quote namespaced model names in class field condition.
|
11
|
+
* [FEATURE] Polymorphic associations can be used within index definitions when the appropriate classes are set out.
|
12
|
+
* [FEATURE] Allow custom strings for SQL joins in index definitions.
|
13
|
+
* [FIX] New lines are maintained and escaped in custom source queries.
|
14
|
+
* [FIX] Subclasses of indexed models fire delta callbacks properly.
|
15
|
+
* [FIX] Thinking Sphinx can be loaded via thinking/sphinx, to satisfy Bundler.
|
16
|
+
* [FEATURE] indexer and searchd settings are added to the appropriate objects from config/thinking_sphinx.yml (@ygelfand).
|
17
|
+
* [FIX] New lines are maintained and escaped in sql_query values.
|
18
|
+
|
1
19
|
2013-01-02: 3.0.0
|
2
20
|
* [CHANGE] Updating Riddle dependency to 1.5.4.
|
3
21
|
* [FIX] Respect source options as well as underlying settings via the set_property method in index definitions.
|
data/README.textile
CHANGED
@@ -1,15 +1,19 @@
|
|
1
1
|
h1. Thinking Sphinx
|
2
2
|
|
3
|
-
Welcome to Thinking Sphinx version 3 - a complete rewrite from past versions
|
4
|
-
|
5
|
-
Still interested? Well, read on!
|
3
|
+
Welcome to Thinking Sphinx version 3 - a complete rewrite from past versions, built for Rails 3.1 or newer only.
|
6
4
|
|
7
5
|
h2. Installation
|
8
6
|
|
9
|
-
|
7
|
+
It's a gem, so install it like you would any other gem. You will also need to specify the Mysql2 gem as well (this is not an inbuilt dependency because JRuby, when supported, will need something different):
|
10
8
|
|
11
9
|
<pre><code>gem 'mysql2', '0.3.12b4'
|
12
|
-
gem 'thinking-sphinx', '3.0.0
|
10
|
+
gem 'thinking-sphinx', '3.0.0'</code></pre>
|
11
|
+
|
12
|
+
The mysql2 gem is required for connecting to Sphinx, so please include it even when you're using PostgreSQL for your database.
|
13
|
+
|
14
|
+
As for Sphinx itself, you need to make sure it's compiled with MySQL support, even if you're using PostgreSQL as your database - which is normally the default, but Homebrew can be too smart sometimes. If that's your compiling tool of choice, make sure you install with the @--mysql@ flag:
|
15
|
+
|
16
|
+
<pre><code>brew install sphinx --mysql</code></pre>
|
13
17
|
|
14
18
|
h2. Usage
|
15
19
|
|
@@ -26,6 +30,11 @@ end</code></pre>
|
|
26
30
|
|
27
31
|
You'll notice the first argument is the model name downcased and as a symbol, and we are specifying the processor - @:active_record@. Everything inside the block is just like previous versions of Thinking Sphinx. Same goes for @config/thinking_sphinx.yml@ (formerly @config/sphinx.yml@).
|
28
32
|
|
33
|
+
When you're defining indices for namespaced models, use a lowercase string with /'s for namespacing as the model reference:
|
34
|
+
|
35
|
+
<pre><code># For a model named Blog::Article:
|
36
|
+
ThinkingSphinx::Index.define 'blog/article', :with => :active_record</code></pre>
|
37
|
+
|
29
38
|
Other changes:
|
30
39
|
* SphinxQL is now used instead of the old socket connections (hence the dependency on the @mysql2@ gem).
|
31
40
|
* You'll need to include @ThinkingSphinx::Scopes@ into your models if you want to use Sphinx scopes. Default scopes can be set as follows:
|
@@ -65,7 +74,7 @@ end</code></pre>
|
|
65
74
|
:classes => [User, AdminUser, SupportUser]</code></pre>
|
66
75
|
|
67
76
|
* The option @:rank_mode@ has now become @:ranker@ - and the options (as strings or symbols) are as follows: proximity_bm25, bm25, none, wordcount, proximity, matchany, and fieldmask.
|
68
|
-
* There are no explicit sorting modes - all sorting must be on attributes followed by ASC or DESC. For example:
|
77
|
+
* There are no explicit sorting modes - all sorting must be on attributes followed by ASC or DESC. For example: <code>:order => '@weight DESC, created_at ASC'</code>.
|
69
78
|
* If you specify just an attribute name as a symbol for the @:order@ option, it will be given the ascending direction by default. So, @:order => :created_at@ is equivalent to @:order => 'created_at ASC'@.
|
70
79
|
* If you want to use a calculated expression for sorting, you must specify the expression as a new attribute, then use that attribute in your @:order@ option. This is done using the @:select@ option to specify extra columns available in the underlying SphinxQL (_not_ ActiveRecord/SQL) query.
|
71
80
|
|
@@ -146,7 +155,11 @@ ThinkingSphinx::Index.define :article, :with => :active_record, :delta => Occasi
|
|
146
155
|
# ...
|
147
156
|
end</code></pre>
|
148
157
|
|
149
|
-
*
|
158
|
+
* Polymorphic associations used within index definitions must be declared with the corresponding models. This is much better than the old approach of querying the database on the *_type column to determine what models to join against.
|
159
|
+
|
160
|
+
<pre><code>indexes events.eventable.name
|
161
|
+
|
162
|
+
polymorphs events.eventable, :to => %w(Page Post User)</code></pre>
|
150
163
|
|
151
164
|
h2. Search Middleware
|
152
165
|
|
@@ -176,6 +189,17 @@ All panes namespaced to @ThinkingSphinx::Panes@, and the @DistancePane@ is autom
|
|
176
189
|
|
177
190
|
If you wish to add your own panes, go ahead. The only requirement is that the initializer must accept three arguments: the search context, the underlying search result object, and a hash of the raw values from Sphinx.
|
178
191
|
|
192
|
+
h2. Deployment with Capistrano
|
193
|
+
|
194
|
+
Thinking Sphinx comes with several Capistrano tasks to help ease deployment of your applications. Just require the recipes:
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
# config/deploy.rb
|
198
|
+
require 'thinking_sphinx/capistrano'
|
199
|
+
```
|
200
|
+
|
201
|
+
When running `cap deploy:setup` to get your server ready for deployments, Thinking Sphinx will also set up a shared folder for your indexes. Before finalizing a deployment, these indexes will be symlinked into the release path for use. When you deploy your application for the first time using `cap deploy:cold`, your indexes will be built for you and the search daemon will be started. Run `cap -T` to see all of the deployment tasks.
|
202
|
+
|
179
203
|
h2. Limitations
|
180
204
|
|
181
205
|
Almost all functionality from v2 releases are implemented, though it's worth noting that some settings haven't yet been brought across, and a handful of the smaller features don't yet exist either. Some may actually not return... we'll see.
|
@@ -186,7 +210,6 @@ May or may not be added:
|
|
186
210
|
* Bitmask weighting helper
|
187
211
|
* Timezone support (for databases not using UTC)
|
188
212
|
* Abstract Inheritance support (maybe - not sure this is something many of people want).
|
189
|
-
* Capistrano Tasks
|
190
213
|
* Facet support for arrays of strings.
|
191
214
|
|
192
215
|
h3. Sphinx Versions
|
data/gemfiles/rails_3_1.gemfile
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
source :rubygems
|
4
4
|
|
5
|
-
gem "
|
6
|
-
gem "combustion", :git=>"git://github.com/pat/combustion.git", :ref=>"45f50e64c3"
|
5
|
+
gem "mysql2", "~> 0.3.12b4", :platform=>:ruby
|
7
6
|
gem "pg", "~> 0.11.0", :platform=>:ruby
|
7
|
+
gem "activerecord-jdbcmysql-adapter", "~> 1.1.3", :platform=>:jruby
|
8
8
|
gem "activerecord-jdbcpostgresql-adapter", "~> 1.1.3", :platform=>:jruby
|
9
9
|
gem "rails", "~> 3.1.0"
|
10
10
|
|
data/gemfiles/rails_3_2.gemfile
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
source :rubygems
|
4
4
|
|
5
|
-
gem "
|
6
|
-
gem "combustion", :git=>"git://github.com/pat/combustion.git", :ref=>"45f50e64c3"
|
5
|
+
gem "mysql2", "~> 0.3.12b4", :platform=>:ruby
|
7
6
|
gem "pg", "~> 0.11.0", :platform=>:ruby
|
7
|
+
gem "activerecord-jdbcmysql-adapter", "~> 1.1.3", :platform=>:jruby
|
8
8
|
gem "activerecord-jdbcpostgresql-adapter", "~> 1.1.3", :platform=>:jruby
|
9
9
|
gem "rails", "~> 3.2.0"
|
10
10
|
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'thinking_sphinx'
|
data/lib/thinking_sphinx.rb
CHANGED
@@ -35,6 +35,7 @@ require 'thinking_sphinx/callbacks'
|
|
35
35
|
require 'thinking_sphinx/core'
|
36
36
|
require 'thinking_sphinx/configuration'
|
37
37
|
require 'thinking_sphinx/connection'
|
38
|
+
require 'thinking_sphinx/errors'
|
38
39
|
require 'thinking_sphinx/excerpter'
|
39
40
|
require 'thinking_sphinx/facet'
|
40
41
|
require 'thinking_sphinx/facet_search'
|
@@ -13,9 +13,11 @@ require 'thinking_sphinx/active_record/base'
|
|
13
13
|
require 'thinking_sphinx/active_record/column'
|
14
14
|
require 'thinking_sphinx/active_record/database_adapters'
|
15
15
|
require 'thinking_sphinx/active_record/field'
|
16
|
+
require 'thinking_sphinx/active_record/filtered_reflection'
|
16
17
|
require 'thinking_sphinx/active_record/index'
|
17
18
|
require 'thinking_sphinx/active_record/interpreter'
|
18
19
|
require 'thinking_sphinx/active_record/log_subscriber'
|
20
|
+
require 'thinking_sphinx/active_record/polymorpher'
|
19
21
|
require 'thinking_sphinx/active_record/property_query'
|
20
22
|
require 'thinking_sphinx/active_record/property_sql_presenter'
|
21
23
|
require 'thinking_sphinx/active_record/sql_builder'
|
@@ -15,7 +15,7 @@ class ThinkingSphinx::ActiveRecord::Associations
|
|
15
15
|
def aggregate_for?(stack)
|
16
16
|
return false if stack.empty?
|
17
17
|
|
18
|
-
joins_for(stack).any? { |join|
|
18
|
+
joins_for(stack).compact.any? { |join|
|
19
19
|
[:has_many, :has_and_belongs_to_many].include?(
|
20
20
|
join.reflection.macro
|
21
21
|
)
|
@@ -29,7 +29,14 @@ class ThinkingSphinx::ActiveRecord::Associations
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def join_values
|
32
|
-
@joins.values
|
32
|
+
@joins.values.compact
|
33
|
+
end
|
34
|
+
|
35
|
+
def model_for(stack)
|
36
|
+
return model if stack.empty?
|
37
|
+
|
38
|
+
join = join_for(stack)
|
39
|
+
join.nil? ? nil : join.reflection.klass
|
33
40
|
end
|
34
41
|
|
35
42
|
private
|
@@ -40,9 +47,14 @@ class ThinkingSphinx::ActiveRecord::Associations
|
|
40
47
|
|
41
48
|
def join_for(stack)
|
42
49
|
@joins[stack] ||= begin
|
43
|
-
|
44
|
-
|
45
|
-
|
50
|
+
reflection = reflection_for stack
|
51
|
+
reflection.nil? ? nil : JoinDependency::JoinAssociation.new(
|
52
|
+
reflection, base, parent_join_for(stack)
|
53
|
+
).tap { |join|
|
54
|
+
join.join_type = Arel::OuterJoin
|
55
|
+
|
56
|
+
rewrite_conditions_for join
|
57
|
+
}
|
46
58
|
end
|
47
59
|
end
|
48
60
|
|
@@ -65,4 +77,12 @@ class ThinkingSphinx::ActiveRecord::Associations
|
|
65
77
|
def reflection_for(stack)
|
66
78
|
parent_for(stack).active_record.reflections[stack.last]
|
67
79
|
end
|
80
|
+
|
81
|
+
def rewrite_conditions_for(join)
|
82
|
+
conditions = Array(join.conditions).flatten
|
83
|
+
conditions.each do |condition|
|
84
|
+
condition.gsub! /::ts_join_alias::/,
|
85
|
+
model.connection.quote_table_name(join.parent.aliased_table_name)
|
86
|
+
end
|
87
|
+
end
|
68
88
|
end
|
@@ -42,14 +42,10 @@ class ThinkingSphinx::ActiveRecord::Callbacks::DeltaCallbacks <
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def indices
|
45
|
-
@indices ||=
|
45
|
+
@indices ||= ThinkingSphinx::IndexSet.new [instance.class], []
|
46
46
|
end
|
47
47
|
|
48
48
|
def processors
|
49
49
|
delta_indices.collect &:delta_processor
|
50
50
|
end
|
51
|
-
|
52
|
-
def reference
|
53
|
-
instance.class.name.underscore.to_sym
|
54
|
-
end
|
55
51
|
end
|
@@ -8,6 +8,18 @@ class ThinkingSphinx::ActiveRecord::Column
|
|
8
8
|
@name
|
9
9
|
end
|
10
10
|
|
11
|
+
def __path
|
12
|
+
@stack + [@name]
|
13
|
+
end
|
14
|
+
|
15
|
+
def __replace(stack, replacements)
|
16
|
+
return [self] if string? || __stack[0..stack.length-1] != stack
|
17
|
+
|
18
|
+
replacements.collect { |replacement|
|
19
|
+
self.class.new *(replacement + __stack[stack.length..-1]), __name
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
11
23
|
def __stack
|
12
24
|
@stack
|
13
25
|
end
|
@@ -28,6 +28,13 @@ module ThinkingSphinx::ActiveRecord::DatabaseAdapters
|
|
28
28
|
:mysql
|
29
29
|
when "jdbcpostgresql"
|
30
30
|
:postgresql
|
31
|
+
when "jdbc"
|
32
|
+
match = /^jdbc:(?<adapter>mysql|postgresql):\/\//.match(model.connection.config[:url])
|
33
|
+
if match
|
34
|
+
match[:adapter].to_sym
|
35
|
+
else
|
36
|
+
model.connection.config[:adapter]
|
37
|
+
end
|
31
38
|
else
|
32
39
|
model.connection.config[:adapter]
|
33
40
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class ThinkingSphinx::ActiveRecord::FilteredReflection <
|
2
|
+
ActiveRecord::Reflection::AssociationReflection
|
3
|
+
|
4
|
+
class Options
|
5
|
+
attr_reader :reflection, :class_name, :options
|
6
|
+
|
7
|
+
delegate :foreign_type, :active_record, :to => :reflection
|
8
|
+
|
9
|
+
def initialize(reflection, class_name)
|
10
|
+
@reflection, @class_name = reflection, class_name
|
11
|
+
@options = reflection.options.clone
|
12
|
+
end
|
13
|
+
|
14
|
+
def filtered
|
15
|
+
options.delete :polymorphic
|
16
|
+
options[:class_name] = class_name
|
17
|
+
options[:foreign_key] ||= "#{reflection.name}_id"
|
18
|
+
|
19
|
+
case options[:conditions]
|
20
|
+
when nil
|
21
|
+
options[:conditions] = condition
|
22
|
+
when Array
|
23
|
+
options[:conditions] << condition
|
24
|
+
when Hash
|
25
|
+
options[:conditions].merge!(reflection.foreign_type => options[:class_name])
|
26
|
+
else
|
27
|
+
options[:conditions] << " AND #{condition}"
|
28
|
+
end
|
29
|
+
|
30
|
+
options
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def condition
|
36
|
+
"::ts_join_alias::.#{quoted_foreign_type} = '#{class_name}'"
|
37
|
+
end
|
38
|
+
|
39
|
+
def quoted_foreign_type
|
40
|
+
active_record.connection.quote_column_name foreign_type
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.clone_with_filter(reflection, name, class_name)
|
45
|
+
options = Options.new(reflection, class_name).filtered
|
46
|
+
|
47
|
+
new reflection.macro, name, options, reflection.active_record
|
48
|
+
end
|
49
|
+
end
|
@@ -28,6 +28,12 @@ class ThinkingSphinx::ActiveRecord::Interpreter <
|
|
28
28
|
}
|
29
29
|
end
|
30
30
|
|
31
|
+
def polymorphs(column, options)
|
32
|
+
__source.polymorphs << ::ThinkingSphinx::ActiveRecord::Polymorpher.new(
|
33
|
+
__source, column, options[:to]
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
31
37
|
def sanitize_sql(*arguments)
|
32
38
|
__source.model.send :sanitize_sql, *arguments
|
33
39
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class ThinkingSphinx::ActiveRecord::Polymorpher
|
2
|
+
def initialize(source, column, class_names)
|
3
|
+
@source, @column, @class_names = source, column, class_names
|
4
|
+
end
|
5
|
+
|
6
|
+
def morph!
|
7
|
+
append_reflections
|
8
|
+
morph_properties
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
attr_reader :source, :column, :class_names
|
14
|
+
|
15
|
+
def append_reflections
|
16
|
+
mappings.each do |class_name, name|
|
17
|
+
klass.reflections[name] ||= ThinkingSphinx::ActiveRecord::
|
18
|
+
FilteredReflection.clone_with_filter(reflection, name, class_name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def mappings
|
23
|
+
@mappings ||= class_names.inject({}) do |hash, class_name|
|
24
|
+
hash[class_name] = "#{column.__name}_#{class_name.downcase}".to_sym
|
25
|
+
hash
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def morphed_stacks
|
30
|
+
@morphed_stacks ||= mappings.values.collect { |key|
|
31
|
+
column.__stack + [key]
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def morph_properties
|
36
|
+
(source.fields + source.attributes).each do |property|
|
37
|
+
property.rebase column.__path, :to => morphed_stacks
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def reflection
|
42
|
+
@reflection ||= klass.reflections[column.__name]
|
43
|
+
end
|
44
|
+
|
45
|
+
def klass
|
46
|
+
@klass ||= column.__stack.inject(source.model) { |parent, key|
|
47
|
+
parent.reflections[key].klass
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
@@ -12,6 +12,12 @@ class ThinkingSphinx::ActiveRecord::Property
|
|
12
12
|
}
|
13
13
|
end
|
14
14
|
|
15
|
+
def rebase(associations, options)
|
16
|
+
@columns = columns.inject([]) do |array, column|
|
17
|
+
array + column.__replace(associations, options[:to])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
15
21
|
def name
|
16
22
|
(options[:as] || columns.first.__name).to_s
|
17
23
|
end
|
@@ -7,7 +7,7 @@ class ThinkingSphinx::ActiveRecord::PropertyQuery
|
|
7
7
|
identifier = [type, property.name].compact.join(' ')
|
8
8
|
queries = []
|
9
9
|
if column.string?
|
10
|
-
queries << column.__name
|
10
|
+
queries << column.__name.strip.gsub(/\n/, "\\\n")
|
11
11
|
else
|
12
12
|
queries << to_sql
|
13
13
|
queries << range_sql if ranged?
|
@@ -38,8 +38,14 @@ class ThinkingSphinx::ActiveRecord::PropertySQLPresenter
|
|
38
38
|
clause
|
39
39
|
end
|
40
40
|
|
41
|
+
def column_exists?(column)
|
42
|
+
model = associations.model_for(column.__stack)
|
43
|
+
model && model.column_names.include?(column.__name.to_s)
|
44
|
+
end
|
45
|
+
|
41
46
|
def column_with_table(column)
|
42
47
|
return column.__name if column.string?
|
48
|
+
return nil unless column_exists?(column)
|
43
49
|
|
44
50
|
"#{associations.alias_for(column.__stack)}.#{adapter.quote column.__name}"
|
45
51
|
end
|
@@ -47,7 +53,7 @@ class ThinkingSphinx::ActiveRecord::PropertySQLPresenter
|
|
47
53
|
def columns_with_table
|
48
54
|
property.columns.collect { |column|
|
49
55
|
column_with_table(column)
|
50
|
-
}.join(', ')
|
56
|
+
}.compact.join(', ')
|
51
57
|
end
|
52
58
|
|
53
59
|
def concatenating?
|