friendlyfashion-thinking-sphinx 2.0.13
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +244 -0
- data/LICENCE +20 -0
- data/README.textile +235 -0
- data/features/abstract_inheritance.feature +10 -0
- data/features/alternate_primary_key.feature +27 -0
- data/features/attribute_transformation.feature +22 -0
- data/features/attribute_updates.feature +77 -0
- data/features/deleting_instances.feature +67 -0
- data/features/direct_attributes.feature +11 -0
- data/features/excerpts.feature +21 -0
- data/features/extensible_delta_indexing.feature +9 -0
- data/features/facets.feature +88 -0
- data/features/facets_across_model.feature +29 -0
- data/features/field_sorting.feature +18 -0
- data/features/handling_edits.feature +94 -0
- data/features/retry_stale_indexes.feature +24 -0
- data/features/searching_across_models.feature +20 -0
- data/features/searching_by_index.feature +40 -0
- data/features/searching_by_model.feature +175 -0
- data/features/searching_with_find_arguments.feature +56 -0
- data/features/sphinx_detection.feature +25 -0
- data/features/sphinx_scopes.feature +68 -0
- data/features/step_definitions/alpha_steps.rb +16 -0
- data/features/step_definitions/beta_steps.rb +7 -0
- data/features/step_definitions/common_steps.rb +201 -0
- data/features/step_definitions/extensible_delta_indexing_steps.rb +7 -0
- data/features/step_definitions/facet_steps.rb +96 -0
- data/features/step_definitions/find_arguments_steps.rb +36 -0
- data/features/step_definitions/gamma_steps.rb +15 -0
- data/features/step_definitions/scope_steps.rb +19 -0
- data/features/step_definitions/search_steps.rb +94 -0
- data/features/step_definitions/sphinx_steps.rb +35 -0
- data/features/sti_searching.feature +19 -0
- data/features/support/env.rb +27 -0
- data/features/support/lib/generic_delta_handler.rb +8 -0
- data/features/thinking_sphinx/database.example.yml +3 -0
- data/features/thinking_sphinx/db/.gitignore +1 -0
- data/features/thinking_sphinx/db/fixtures/alphas.rb +8 -0
- data/features/thinking_sphinx/db/fixtures/authors.rb +1 -0
- data/features/thinking_sphinx/db/fixtures/betas.rb +11 -0
- data/features/thinking_sphinx/db/fixtures/boxes.rb +9 -0
- data/features/thinking_sphinx/db/fixtures/categories.rb +1 -0
- data/features/thinking_sphinx/db/fixtures/cats.rb +3 -0
- data/features/thinking_sphinx/db/fixtures/comments.rb +24 -0
- data/features/thinking_sphinx/db/fixtures/developers.rb +31 -0
- data/features/thinking_sphinx/db/fixtures/dogs.rb +3 -0
- data/features/thinking_sphinx/db/fixtures/extensible_betas.rb +10 -0
- data/features/thinking_sphinx/db/fixtures/foxes.rb +3 -0
- data/features/thinking_sphinx/db/fixtures/gammas.rb +10 -0
- data/features/thinking_sphinx/db/fixtures/music.rb +4 -0
- data/features/thinking_sphinx/db/fixtures/people.rb +1001 -0
- data/features/thinking_sphinx/db/fixtures/post_keywords.txt +1 -0
- data/features/thinking_sphinx/db/fixtures/posts.rb +10 -0
- data/features/thinking_sphinx/db/fixtures/robots.rb +8 -0
- data/features/thinking_sphinx/db/fixtures/tags.rb +27 -0
- data/features/thinking_sphinx/db/migrations/create_alphas.rb +8 -0
- data/features/thinking_sphinx/db/migrations/create_animals.rb +5 -0
- data/features/thinking_sphinx/db/migrations/create_authors.rb +3 -0
- data/features/thinking_sphinx/db/migrations/create_authors_posts.rb +6 -0
- data/features/thinking_sphinx/db/migrations/create_betas.rb +5 -0
- data/features/thinking_sphinx/db/migrations/create_boxes.rb +5 -0
- data/features/thinking_sphinx/db/migrations/create_categories.rb +3 -0
- data/features/thinking_sphinx/db/migrations/create_comments.rb +10 -0
- data/features/thinking_sphinx/db/migrations/create_developers.rb +7 -0
- data/features/thinking_sphinx/db/migrations/create_extensible_betas.rb +5 -0
- data/features/thinking_sphinx/db/migrations/create_gammas.rb +3 -0
- data/features/thinking_sphinx/db/migrations/create_genres.rb +3 -0
- data/features/thinking_sphinx/db/migrations/create_music.rb +6 -0
- data/features/thinking_sphinx/db/migrations/create_people.rb +13 -0
- data/features/thinking_sphinx/db/migrations/create_posts.rb +6 -0
- data/features/thinking_sphinx/db/migrations/create_robots.rb +4 -0
- data/features/thinking_sphinx/db/migrations/create_taggings.rb +5 -0
- data/features/thinking_sphinx/db/migrations/create_tags.rb +4 -0
- data/features/thinking_sphinx/models/alpha.rb +23 -0
- data/features/thinking_sphinx/models/andrew.rb +17 -0
- data/features/thinking_sphinx/models/animal.rb +5 -0
- data/features/thinking_sphinx/models/author.rb +3 -0
- data/features/thinking_sphinx/models/beta.rb +13 -0
- data/features/thinking_sphinx/models/box.rb +8 -0
- data/features/thinking_sphinx/models/cat.rb +3 -0
- data/features/thinking_sphinx/models/category.rb +4 -0
- data/features/thinking_sphinx/models/comment.rb +10 -0
- data/features/thinking_sphinx/models/developer.rb +21 -0
- data/features/thinking_sphinx/models/dog.rb +3 -0
- data/features/thinking_sphinx/models/extensible_beta.rb +9 -0
- data/features/thinking_sphinx/models/fox.rb +5 -0
- data/features/thinking_sphinx/models/gamma.rb +5 -0
- data/features/thinking_sphinx/models/genre.rb +3 -0
- data/features/thinking_sphinx/models/medium.rb +5 -0
- data/features/thinking_sphinx/models/music.rb +10 -0
- data/features/thinking_sphinx/models/person.rb +24 -0
- data/features/thinking_sphinx/models/post.rb +22 -0
- data/features/thinking_sphinx/models/robot.rb +12 -0
- data/features/thinking_sphinx/models/tag.rb +3 -0
- data/features/thinking_sphinx/models/tagging.rb +4 -0
- data/lib/cucumber/thinking_sphinx/external_world.rb +12 -0
- data/lib/cucumber/thinking_sphinx/internal_world.rb +137 -0
- data/lib/cucumber/thinking_sphinx/sql_logger.rb +28 -0
- data/lib/thinking-sphinx.rb +1 -0
- data/lib/thinking_sphinx/action_controller.rb +31 -0
- data/lib/thinking_sphinx/active_record/attribute_updates.rb +53 -0
- data/lib/thinking_sphinx/active_record/collection_proxy.rb +47 -0
- data/lib/thinking_sphinx/active_record/collection_proxy_with_scopes.rb +27 -0
- data/lib/thinking_sphinx/active_record/delta.rb +67 -0
- data/lib/thinking_sphinx/active_record/has_many_association.rb +44 -0
- data/lib/thinking_sphinx/active_record/has_many_association_with_scopes.rb +21 -0
- data/lib/thinking_sphinx/active_record/log_subscriber.rb +61 -0
- data/lib/thinking_sphinx/active_record/scopes.rb +110 -0
- data/lib/thinking_sphinx/active_record.rb +386 -0
- data/lib/thinking_sphinx/adapters/abstract_adapter.rb +87 -0
- data/lib/thinking_sphinx/adapters/mysql_adapter.rb +62 -0
- data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +188 -0
- data/lib/thinking_sphinx/association.rb +230 -0
- data/lib/thinking_sphinx/attribute.rb +405 -0
- data/lib/thinking_sphinx/auto_version.rb +40 -0
- data/lib/thinking_sphinx/bundled_search.rb +44 -0
- data/lib/thinking_sphinx/class_facet.rb +20 -0
- data/lib/thinking_sphinx/configuration.rb +375 -0
- data/lib/thinking_sphinx/context.rb +76 -0
- data/lib/thinking_sphinx/core/string.rb +15 -0
- data/lib/thinking_sphinx/deltas/default_delta.rb +62 -0
- data/lib/thinking_sphinx/deltas.rb +28 -0
- data/lib/thinking_sphinx/deploy/capistrano.rb +99 -0
- data/lib/thinking_sphinx/excerpter.rb +23 -0
- data/lib/thinking_sphinx/facet.rb +135 -0
- data/lib/thinking_sphinx/facet_search.rb +170 -0
- data/lib/thinking_sphinx/field.rb +98 -0
- data/lib/thinking_sphinx/index/builder.rb +315 -0
- data/lib/thinking_sphinx/index/faux_column.rb +118 -0
- data/lib/thinking_sphinx/index.rb +159 -0
- data/lib/thinking_sphinx/join.rb +37 -0
- data/lib/thinking_sphinx/property.rb +187 -0
- data/lib/thinking_sphinx/railtie.rb +43 -0
- data/lib/thinking_sphinx/search.rb +1061 -0
- data/lib/thinking_sphinx/search_methods.rb +439 -0
- data/lib/thinking_sphinx/sinatra.rb +7 -0
- data/lib/thinking_sphinx/source/internal_properties.rb +51 -0
- data/lib/thinking_sphinx/source/sql.rb +174 -0
- data/lib/thinking_sphinx/source.rb +194 -0
- data/lib/thinking_sphinx/tasks.rb +142 -0
- data/lib/thinking_sphinx/test.rb +55 -0
- data/lib/thinking_sphinx/version.rb +3 -0
- data/lib/thinking_sphinx.rb +297 -0
- data/spec/fixtures/data.sql +32 -0
- data/spec/fixtures/database.yml.default +3 -0
- data/spec/fixtures/models.rb +164 -0
- data/spec/fixtures/structure.sql +146 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/sphinx_helper.rb +60 -0
- data/spec/support/rails.rb +25 -0
- data/spec/thinking_sphinx/active_record/delta_spec.rb +122 -0
- data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +173 -0
- data/spec/thinking_sphinx/active_record/scopes_spec.rb +176 -0
- data/spec/thinking_sphinx/active_record_spec.rb +573 -0
- data/spec/thinking_sphinx/adapters/abstract_adapter_spec.rb +145 -0
- data/spec/thinking_sphinx/association_spec.rb +250 -0
- data/spec/thinking_sphinx/attribute_spec.rb +552 -0
- data/spec/thinking_sphinx/auto_version_spec.rb +103 -0
- data/spec/thinking_sphinx/configuration_spec.rb +326 -0
- data/spec/thinking_sphinx/context_spec.rb +126 -0
- data/spec/thinking_sphinx/core/array_spec.rb +9 -0
- data/spec/thinking_sphinx/core/string_spec.rb +9 -0
- data/spec/thinking_sphinx/excerpter_spec.rb +49 -0
- data/spec/thinking_sphinx/facet_search_spec.rb +176 -0
- data/spec/thinking_sphinx/facet_spec.rb +359 -0
- data/spec/thinking_sphinx/field_spec.rb +127 -0
- data/spec/thinking_sphinx/index/builder_spec.rb +532 -0
- data/spec/thinking_sphinx/index/faux_column_spec.rb +36 -0
- data/spec/thinking_sphinx/index_spec.rb +189 -0
- data/spec/thinking_sphinx/search_methods_spec.rb +156 -0
- data/spec/thinking_sphinx/search_spec.rb +1455 -0
- data/spec/thinking_sphinx/source_spec.rb +267 -0
- data/spec/thinking_sphinx/test_spec.rb +20 -0
- data/spec/thinking_sphinx_spec.rb +204 -0
- metadata +524 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
module ThinkingSphinx
|
2
|
+
module ActiveRecord
|
3
|
+
module AttributeUpdates
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
after_save :update_attribute_values
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def update_attribute_values
|
13
|
+
return true unless ThinkingSphinx.updates_enabled? &&
|
14
|
+
ThinkingSphinx.sphinx_running?
|
15
|
+
|
16
|
+
self.class.sphinx_indexes.each do |index|
|
17
|
+
attribute_pairs = attribute_values_for_index(index)
|
18
|
+
attribute_names = attribute_pairs.keys
|
19
|
+
attribute_values = attribute_names.collect { |key|
|
20
|
+
attribute_pairs[key]
|
21
|
+
}
|
22
|
+
|
23
|
+
update_index index.core_name, attribute_names, attribute_values
|
24
|
+
next unless index.delta?
|
25
|
+
update_index index.delta_name, attribute_names, attribute_values
|
26
|
+
end
|
27
|
+
|
28
|
+
true
|
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
|
+
hash[attrib.unique_name.to_s] = attrib.live_value self
|
38
|
+
hash
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def update_index(index_name, attribute_names, attribute_values)
|
43
|
+
config = ThinkingSphinx::Configuration.instance
|
44
|
+
config.client.update index_name, attribute_names, {
|
45
|
+
sphinx_document_id => attribute_values
|
46
|
+
}
|
47
|
+
rescue Riddle::ConnectionError, Riddle::ResponseError,
|
48
|
+
ThinkingSphinx::SphinxError, Errno::ETIMEDOUT
|
49
|
+
# Not the end of the world if Sphinx isn't running.
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ThinkingSphinx
|
2
|
+
module ActiveRecord
|
3
|
+
module CollectionProxy
|
4
|
+
def search(*args)
|
5
|
+
proxy_association.klass.search(*association_args(args))
|
6
|
+
end
|
7
|
+
|
8
|
+
def facets(*args)
|
9
|
+
proxy_association.klass.facets(*association_args(args))
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def association_args(args)
|
15
|
+
options = args.extract_options!
|
16
|
+
options[:with] ||= {}
|
17
|
+
options[:with].merge! default_filter
|
18
|
+
|
19
|
+
args + [options]
|
20
|
+
end
|
21
|
+
|
22
|
+
def attribute_for_foreign_key
|
23
|
+
if proxy_association.reflection.through_reflection
|
24
|
+
foreign_key = proxy_association.reflection.through_reflection.foreign_key
|
25
|
+
else
|
26
|
+
foreign_key = proxy_association.reflection.foreign_key
|
27
|
+
end
|
28
|
+
|
29
|
+
proxy_association.klass.define_indexes
|
30
|
+
(proxy_association.klass.sphinx_indexes || []).each do |index|
|
31
|
+
attribute = index.attributes.detect { |attrib|
|
32
|
+
attrib.columns.length == 1 &&
|
33
|
+
attrib.columns.first.__name == foreign_key.to_sym ||
|
34
|
+
attrib.alias == foreign_key.to_sym
|
35
|
+
}
|
36
|
+
return attribute unless attribute.nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
raise "Missing Attribute for Foreign Key #{foreign_key}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def default_filter
|
43
|
+
{attribute_for_foreign_key.unique_name => proxy_association.owner.id}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ThinkingSphinx
|
2
|
+
module ActiveRecord
|
3
|
+
module CollectionProxyWithScopes
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
alias_method_chain :method_missing, :sphinx_scopes
|
7
|
+
alias_method_chain :respond_to?, :sphinx_scopes
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing_with_sphinx_scopes(method, *args, &block)
|
12
|
+
klass = proxy_association.klass
|
13
|
+
if klass.respond_to?(:sphinx_scopes) && klass.sphinx_scopes.include?(method)
|
14
|
+
klass.search(:with => default_filter).send(method, *args, &block)
|
15
|
+
else
|
16
|
+
method_missing_without_sphinx_scopes(method, *args, &block)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def respond_to_with_sphinx_scopes?(method)
|
21
|
+
proxy_association.klass.respond_to?(:sphinx_scopes) &&
|
22
|
+
proxy_association.klass.sphinx_scopes.include?(method) ||
|
23
|
+
respond_to_without_sphinx_scopes?(method)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ThinkingSphinx
|
2
|
+
module ActiveRecord
|
3
|
+
# This module contains all the delta-related code for models. There isn't
|
4
|
+
# really anything you need to call manually in here - except perhaps
|
5
|
+
# index_delta, but not sure what reason why.
|
6
|
+
#
|
7
|
+
module Delta
|
8
|
+
# Code for after_commit callback is written by Eli Miller:
|
9
|
+
# http://elimiller.blogspot.com/2007/06/proper-cache-expiry-with-aftercommit.html
|
10
|
+
# with slight modification from Joost Hietbrink.
|
11
|
+
#
|
12
|
+
def self.included(base)
|
13
|
+
base.class_eval do
|
14
|
+
class << self
|
15
|
+
# Build the delta index for the related model. This won't be called
|
16
|
+
# if running in the test environment.
|
17
|
+
#
|
18
|
+
def index_delta(instance = nil)
|
19
|
+
delta_objects.each { |obj| obj.index(self, instance) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def delta_objects
|
23
|
+
self.sphinx_indexes.collect(&:delta_object).compact
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def toggled_delta?
|
28
|
+
self.class.delta_objects.any? { |obj| obj.toggled(self) }
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# Set the delta value for the model to be true.
|
34
|
+
def toggle_delta
|
35
|
+
self.class.delta_objects.each { |obj|
|
36
|
+
obj.toggle(self)
|
37
|
+
} if should_toggle_delta?
|
38
|
+
end
|
39
|
+
|
40
|
+
# Build the delta index for the related model. This won't be called
|
41
|
+
# if running in the test environment.
|
42
|
+
#
|
43
|
+
def index_delta
|
44
|
+
self.class.index_delta(self) if self.class.delta_objects.any? { |obj|
|
45
|
+
obj.toggled(self)
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
def should_toggle_delta?
|
50
|
+
return fire_delta? if respond_to?(:fire_delta?)
|
51
|
+
|
52
|
+
self.new_record? || indexed_data_changed?
|
53
|
+
end
|
54
|
+
|
55
|
+
def indexed_data_changed?
|
56
|
+
sphinx_indexes.any? { |index|
|
57
|
+
index.fields.any? { |field| field.changed?(self) } ||
|
58
|
+
index.attributes.any? { |attrib|
|
59
|
+
attrib.public? && attrib.changed?(self) && !attrib.updatable?
|
60
|
+
}
|
61
|
+
}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module ThinkingSphinx
|
2
|
+
module ActiveRecord
|
3
|
+
module HasManyAssociation
|
4
|
+
def search(*args)
|
5
|
+
@reflection.klass.search(*association_args(args))
|
6
|
+
end
|
7
|
+
|
8
|
+
def facets(*args)
|
9
|
+
@reflection.klass.facets(*association_args(args))
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def association_args(args)
|
15
|
+
options = args.extract_options!
|
16
|
+
options[:with] ||= {}
|
17
|
+
options[:with].merge! default_filter
|
18
|
+
|
19
|
+
args + [options]
|
20
|
+
end
|
21
|
+
|
22
|
+
def attribute_for_foreign_key
|
23
|
+
foreign_key = @reflection.primary_key_name
|
24
|
+
stack = [@reflection.options[:through]].compact
|
25
|
+
|
26
|
+
@reflection.klass.define_indexes
|
27
|
+
(@reflection.klass.sphinx_indexes || []).each do |index|
|
28
|
+
attribute = index.attributes.detect { |attrib|
|
29
|
+
attrib.columns.length == 1 &&
|
30
|
+
attrib.columns.first.__name == foreign_key.to_sym ||
|
31
|
+
attrib.alias == foreign_key.to_sym
|
32
|
+
}
|
33
|
+
return attribute unless attribute.nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
raise "Missing Attribute for Foreign Key #{foreign_key}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def default_filter
|
40
|
+
{attribute_for_foreign_key.unique_name => @owner.id}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ThinkingSphinx
|
2
|
+
module ActiveRecord
|
3
|
+
module HasManyAssociationWithScopes
|
4
|
+
def method_missing(method, *args, &block)
|
5
|
+
if responds_to_scope(method)
|
6
|
+
@reflection.klass.
|
7
|
+
search(:with => default_filter).
|
8
|
+
send(method, *args, &block)
|
9
|
+
else
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def responds_to_scope(scope)
|
16
|
+
@reflection.klass.respond_to?(:sphinx_scopes) &&
|
17
|
+
@reflection.klass.sphinx_scopes.include?(scope)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'active_support/log_subscriber'
|
2
|
+
|
3
|
+
module ThinkingSphinx
|
4
|
+
module ActiveRecord
|
5
|
+
class LogSubscriber < ActiveSupport::LogSubscriber
|
6
|
+
def self.runtime=(value)
|
7
|
+
Thread.current['thinking_sphinx_query_runtime'] = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.runtime
|
11
|
+
Thread.current['thinking_sphinx_query_runtime'] ||= 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.reset_runtime
|
15
|
+
rt, self.runtime = runtime, 0
|
16
|
+
rt
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
super
|
21
|
+
@odd_or_even = false
|
22
|
+
end
|
23
|
+
|
24
|
+
def query(event)
|
25
|
+
self.class.runtime += event.duration
|
26
|
+
return unless logger.debug?
|
27
|
+
|
28
|
+
identifier = color('Sphinx Query (%.1fms)' % event.duration, GREEN, true)
|
29
|
+
query = event.payload[:query]
|
30
|
+
query = color query, nil, true if odd?
|
31
|
+
|
32
|
+
debug " #{identifier} #{query}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def message(event)
|
36
|
+
return unless logger.debug?
|
37
|
+
|
38
|
+
identifier = color 'Sphinx', GREEN, true
|
39
|
+
message = event.payload[:message]
|
40
|
+
message = color message, nil, true if odd?
|
41
|
+
|
42
|
+
debug " #{identifier} #{message}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def odd?
|
46
|
+
@odd_or_even = !@odd_or_even
|
47
|
+
end
|
48
|
+
|
49
|
+
def logger
|
50
|
+
return @logger if defined? @logger
|
51
|
+
self.logger = ::ActiveRecord::Base.logger
|
52
|
+
end
|
53
|
+
|
54
|
+
def logger=(logger)
|
55
|
+
@logger = logger
|
56
|
+
end
|
57
|
+
|
58
|
+
attach_to :thinking_sphinx
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,110 @@
|
|
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
|
+
|
12
|
+
# Similar to ActiveRecord's default_scope method Thinking Sphinx supports
|
13
|
+
# a default_sphinx_scope. For example:
|
14
|
+
#
|
15
|
+
# default_sphinx_scope :some_sphinx_named_scope
|
16
|
+
#
|
17
|
+
# The scope is automatically applied when the search method is called. It
|
18
|
+
# will only be applied if it is an existing sphinx_scope.
|
19
|
+
def default_sphinx_scope(sphinx_scope_name)
|
20
|
+
add_sphinx_scopes_support_to_has_many_associations
|
21
|
+
@default_sphinx_scope = sphinx_scope_name
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the default_sphinx_scope or nil if none is set.
|
25
|
+
def get_default_sphinx_scope
|
26
|
+
@default_sphinx_scope
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns true if the current Model has a default_sphinx_scope. Also checks if
|
30
|
+
# the default_sphinx_scope actually is a scope.
|
31
|
+
def has_default_sphinx_scope?
|
32
|
+
!@default_sphinx_scope.nil? && sphinx_scopes.include?(@default_sphinx_scope)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Similar to ActiveRecord's named_scope method Thinking Sphinx supports
|
36
|
+
# scopes. For example:
|
37
|
+
#
|
38
|
+
# sphinx_scope(:latest_first) {
|
39
|
+
# {:order => 'created_at DESC, @relevance DESC'}
|
40
|
+
# }
|
41
|
+
#
|
42
|
+
# Usage:
|
43
|
+
#
|
44
|
+
# @articles = Article.latest_first.search 'pancakes'
|
45
|
+
#
|
46
|
+
def sphinx_scope(method, &block)
|
47
|
+
add_sphinx_scopes_support_to_has_many_associations
|
48
|
+
|
49
|
+
@sphinx_scopes ||= []
|
50
|
+
@sphinx_scopes << method
|
51
|
+
|
52
|
+
singleton_class.instance_eval do
|
53
|
+
define_method(method) do |*args|
|
54
|
+
options = {:classes => classes_option}
|
55
|
+
options.merge! block.call(*args)
|
56
|
+
|
57
|
+
ThinkingSphinx::Search.new(options)
|
58
|
+
end
|
59
|
+
|
60
|
+
define_method("#{method}_without_default".to_sym) do |*args|
|
61
|
+
options = {:classes => classes_option, :ignore_default => true}
|
62
|
+
options.merge! block.call(*args)
|
63
|
+
|
64
|
+
ThinkingSphinx::Search.new(options)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# This returns an Array of all defined scopes. The default
|
70
|
+
# scope shows as :default.
|
71
|
+
def sphinx_scopes
|
72
|
+
@sphinx_scopes || []
|
73
|
+
end
|
74
|
+
|
75
|
+
def remove_sphinx_scopes
|
76
|
+
sphinx_scopes.each do |scope|
|
77
|
+
singleton_class.send(:undef_method, scope)
|
78
|
+
end
|
79
|
+
|
80
|
+
sphinx_scopes.clear
|
81
|
+
end
|
82
|
+
|
83
|
+
def add_sphinx_scopes_support_to_has_many_associations
|
84
|
+
mixin = sphinx_scopes_support_mixin
|
85
|
+
sphinx_scopes_support_classes.each do |klass|
|
86
|
+
klass.send(:include, mixin) unless klass.ancestors.include?(mixin)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def sphinx_scopes_support_classes
|
91
|
+
if ThinkingSphinx.rails_3_1?
|
92
|
+
[::ActiveRecord::Associations::CollectionProxy]
|
93
|
+
else
|
94
|
+
[::ActiveRecord::Associations::HasManyAssociation,
|
95
|
+
::ActiveRecord::Associations::HasManyThroughAssociation]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def sphinx_scopes_support_mixin
|
100
|
+
if ThinkingSphinx.rails_3_1?
|
101
|
+
::ThinkingSphinx::ActiveRecord::CollectionProxyWithScopes
|
102
|
+
else
|
103
|
+
::ThinkingSphinx::ActiveRecord::HasManyAssociationWithScopes
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|