joshcutler-thinking-sphinx 1.3.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. data/LICENCE +20 -0
  2. data/README.textile +167 -0
  3. data/VERSION +1 -0
  4. data/features/abstract_inheritance.feature +10 -0
  5. data/features/alternate_primary_key.feature +27 -0
  6. data/features/attribute_transformation.feature +22 -0
  7. data/features/attribute_updates.feature +77 -0
  8. data/features/deleting_instances.feature +67 -0
  9. data/features/direct_attributes.feature +11 -0
  10. data/features/excerpts.feature +13 -0
  11. data/features/extensible_delta_indexing.feature +9 -0
  12. data/features/facets.feature +82 -0
  13. data/features/facets_across_model.feature +29 -0
  14. data/features/handling_edits.feature +92 -0
  15. data/features/retry_stale_indexes.feature +24 -0
  16. data/features/searching_across_models.feature +20 -0
  17. data/features/searching_by_index.feature +40 -0
  18. data/features/searching_by_model.feature +175 -0
  19. data/features/searching_with_find_arguments.feature +56 -0
  20. data/features/sphinx_detection.feature +25 -0
  21. data/features/sphinx_scopes.feature +42 -0
  22. data/features/step_definitions/alpha_steps.rb +16 -0
  23. data/features/step_definitions/beta_steps.rb +7 -0
  24. data/features/step_definitions/common_steps.rb +193 -0
  25. data/features/step_definitions/extensible_delta_indexing_steps.rb +7 -0
  26. data/features/step_definitions/facet_steps.rb +96 -0
  27. data/features/step_definitions/find_arguments_steps.rb +36 -0
  28. data/features/step_definitions/gamma_steps.rb +15 -0
  29. data/features/step_definitions/scope_steps.rb +15 -0
  30. data/features/step_definitions/search_steps.rb +89 -0
  31. data/features/step_definitions/sphinx_steps.rb +35 -0
  32. data/features/sti_searching.feature +19 -0
  33. data/features/support/env.rb +21 -0
  34. data/features/support/lib/generic_delta_handler.rb +8 -0
  35. data/features/thinking_sphinx/database.example.yml +3 -0
  36. data/features/thinking_sphinx/db/fixtures/alphas.rb +10 -0
  37. data/features/thinking_sphinx/db/fixtures/authors.rb +1 -0
  38. data/features/thinking_sphinx/db/fixtures/betas.rb +11 -0
  39. data/features/thinking_sphinx/db/fixtures/boxes.rb +9 -0
  40. data/features/thinking_sphinx/db/fixtures/categories.rb +1 -0
  41. data/features/thinking_sphinx/db/fixtures/cats.rb +3 -0
  42. data/features/thinking_sphinx/db/fixtures/comments.rb +24 -0
  43. data/features/thinking_sphinx/db/fixtures/developers.rb +31 -0
  44. data/features/thinking_sphinx/db/fixtures/dogs.rb +3 -0
  45. data/features/thinking_sphinx/db/fixtures/extensible_betas.rb +10 -0
  46. data/features/thinking_sphinx/db/fixtures/foxes.rb +3 -0
  47. data/features/thinking_sphinx/db/fixtures/gammas.rb +10 -0
  48. data/features/thinking_sphinx/db/fixtures/music.rb +4 -0
  49. data/features/thinking_sphinx/db/fixtures/people.rb +1001 -0
  50. data/features/thinking_sphinx/db/fixtures/posts.rb +6 -0
  51. data/features/thinking_sphinx/db/fixtures/robots.rb +14 -0
  52. data/features/thinking_sphinx/db/fixtures/tags.rb +27 -0
  53. data/features/thinking_sphinx/db/migrations/create_alphas.rb +8 -0
  54. data/features/thinking_sphinx/db/migrations/create_animals.rb +5 -0
  55. data/features/thinking_sphinx/db/migrations/create_authors.rb +3 -0
  56. data/features/thinking_sphinx/db/migrations/create_authors_posts.rb +6 -0
  57. data/features/thinking_sphinx/db/migrations/create_betas.rb +5 -0
  58. data/features/thinking_sphinx/db/migrations/create_boxes.rb +5 -0
  59. data/features/thinking_sphinx/db/migrations/create_categories.rb +3 -0
  60. data/features/thinking_sphinx/db/migrations/create_comments.rb +10 -0
  61. data/features/thinking_sphinx/db/migrations/create_developers.rb +7 -0
  62. data/features/thinking_sphinx/db/migrations/create_extensible_betas.rb +5 -0
  63. data/features/thinking_sphinx/db/migrations/create_gammas.rb +3 -0
  64. data/features/thinking_sphinx/db/migrations/create_genres.rb +3 -0
  65. data/features/thinking_sphinx/db/migrations/create_music.rb +6 -0
  66. data/features/thinking_sphinx/db/migrations/create_people.rb +13 -0
  67. data/features/thinking_sphinx/db/migrations/create_posts.rb +5 -0
  68. data/features/thinking_sphinx/db/migrations/create_robots.rb +4 -0
  69. data/features/thinking_sphinx/db/migrations/create_taggings.rb +5 -0
  70. data/features/thinking_sphinx/db/migrations/create_tags.rb +4 -0
  71. data/features/thinking_sphinx/models/alpha.rb +22 -0
  72. data/features/thinking_sphinx/models/animal.rb +5 -0
  73. data/features/thinking_sphinx/models/author.rb +3 -0
  74. data/features/thinking_sphinx/models/beta.rb +8 -0
  75. data/features/thinking_sphinx/models/box.rb +8 -0
  76. data/features/thinking_sphinx/models/cat.rb +3 -0
  77. data/features/thinking_sphinx/models/category.rb +4 -0
  78. data/features/thinking_sphinx/models/comment.rb +10 -0
  79. data/features/thinking_sphinx/models/developer.rb +16 -0
  80. data/features/thinking_sphinx/models/dog.rb +3 -0
  81. data/features/thinking_sphinx/models/extensible_beta.rb +9 -0
  82. data/features/thinking_sphinx/models/fox.rb +5 -0
  83. data/features/thinking_sphinx/models/gamma.rb +5 -0
  84. data/features/thinking_sphinx/models/genre.rb +3 -0
  85. data/features/thinking_sphinx/models/medium.rb +5 -0
  86. data/features/thinking_sphinx/models/music.rb +8 -0
  87. data/features/thinking_sphinx/models/person.rb +23 -0
  88. data/features/thinking_sphinx/models/post.rb +21 -0
  89. data/features/thinking_sphinx/models/robot.rb +12 -0
  90. data/features/thinking_sphinx/models/tag.rb +3 -0
  91. data/features/thinking_sphinx/models/tagging.rb +4 -0
  92. data/lib/cucumber/thinking_sphinx/external_world.rb +8 -0
  93. data/lib/cucumber/thinking_sphinx/internal_world.rb +126 -0
  94. data/lib/cucumber/thinking_sphinx/sql_logger.rb +20 -0
  95. data/lib/thinking_sphinx.rb +242 -0
  96. data/lib/thinking_sphinx/active_record.rb +380 -0
  97. data/lib/thinking_sphinx/active_record/attribute_updates.rb +50 -0
  98. data/lib/thinking_sphinx/active_record/delta.rb +61 -0
  99. data/lib/thinking_sphinx/active_record/has_many_association.rb +51 -0
  100. data/lib/thinking_sphinx/active_record/scopes.rb +75 -0
  101. data/lib/thinking_sphinx/adapters/abstract_adapter.rb +46 -0
  102. data/lib/thinking_sphinx/adapters/mysql_adapter.rb +58 -0
  103. data/lib/thinking_sphinx/adapters/postgresql_adapter.rb +147 -0
  104. data/lib/thinking_sphinx/association.rb +164 -0
  105. data/lib/thinking_sphinx/attribute.rb +390 -0
  106. data/lib/thinking_sphinx/auto_version.rb +22 -0
  107. data/lib/thinking_sphinx/class_facet.rb +15 -0
  108. data/lib/thinking_sphinx/configuration.rb +292 -0
  109. data/lib/thinking_sphinx/context.rb +74 -0
  110. data/lib/thinking_sphinx/core/array.rb +7 -0
  111. data/lib/thinking_sphinx/core/string.rb +15 -0
  112. data/lib/thinking_sphinx/deltas.rb +28 -0
  113. data/lib/thinking_sphinx/deltas/default_delta.rb +62 -0
  114. data/lib/thinking_sphinx/deploy/capistrano.rb +100 -0
  115. data/lib/thinking_sphinx/excerpter.rb +22 -0
  116. data/lib/thinking_sphinx/facet.rb +125 -0
  117. data/lib/thinking_sphinx/facet_search.rb +136 -0
  118. data/lib/thinking_sphinx/field.rb +80 -0
  119. data/lib/thinking_sphinx/index.rb +157 -0
  120. data/lib/thinking_sphinx/index/builder.rb +302 -0
  121. data/lib/thinking_sphinx/index/faux_column.rb +118 -0
  122. data/lib/thinking_sphinx/join.rb +37 -0
  123. data/lib/thinking_sphinx/property.rb +168 -0
  124. data/lib/thinking_sphinx/rails_additions.rb +150 -0
  125. data/lib/thinking_sphinx/search.rb +785 -0
  126. data/lib/thinking_sphinx/search_methods.rb +439 -0
  127. data/lib/thinking_sphinx/source.rb +159 -0
  128. data/lib/thinking_sphinx/source/internal_properties.rb +46 -0
  129. data/lib/thinking_sphinx/source/sql.rb +130 -0
  130. data/lib/thinking_sphinx/tasks.rb +121 -0
  131. data/lib/thinking_sphinx/test.rb +52 -0
  132. data/rails/init.rb +16 -0
  133. data/spec/thinking_sphinx/active_record/delta_spec.rb +128 -0
  134. data/spec/thinking_sphinx/active_record/has_many_association_spec.rb +71 -0
  135. data/spec/thinking_sphinx/active_record/scopes_spec.rb +177 -0
  136. data/spec/thinking_sphinx/active_record_spec.rb +618 -0
  137. data/spec/thinking_sphinx/association_spec.rb +239 -0
  138. data/spec/thinking_sphinx/attribute_spec.rb +548 -0
  139. data/spec/thinking_sphinx/auto_version_spec.rb +39 -0
  140. data/spec/thinking_sphinx/configuration_spec.rb +271 -0
  141. data/spec/thinking_sphinx/context_spec.rb +126 -0
  142. data/spec/thinking_sphinx/core/array_spec.rb +9 -0
  143. data/spec/thinking_sphinx/core/string_spec.rb +9 -0
  144. data/spec/thinking_sphinx/excerpter_spec.rb +49 -0
  145. data/spec/thinking_sphinx/facet_search_spec.rb +176 -0
  146. data/spec/thinking_sphinx/facet_spec.rb +333 -0
  147. data/spec/thinking_sphinx/field_spec.rb +113 -0
  148. data/spec/thinking_sphinx/index/builder_spec.rb +495 -0
  149. data/spec/thinking_sphinx/index/faux_column_spec.rb +36 -0
  150. data/spec/thinking_sphinx/index_spec.rb +183 -0
  151. data/spec/thinking_sphinx/rails_additions_spec.rb +203 -0
  152. data/spec/thinking_sphinx/search_methods_spec.rb +152 -0
  153. data/spec/thinking_sphinx/search_spec.rb +1206 -0
  154. data/spec/thinking_sphinx/source_spec.rb +243 -0
  155. data/spec/thinking_sphinx_spec.rb +204 -0
  156. data/tasks/distribution.rb +46 -0
  157. data/tasks/rails.rake +1 -0
  158. metadata +475 -0
@@ -0,0 +1,46 @@
1
+ module ThinkingSphinx
2
+ class Source
3
+ module InternalProperties
4
+ def add_internal_attributes_and_facets
5
+ add_internal_attribute :sphinx_internal_id, nil,
6
+ @model.primary_key_for_sphinx.to_sym
7
+ add_internal_attribute :class_crc, :integer, crc_column, true
8
+ add_internal_attribute :sphinx_deleted, :integer, "0"
9
+
10
+ add_internal_facet :class_crc
11
+ end
12
+
13
+ def add_internal_attribute(name, type, contents, facet = false)
14
+ return unless attribute_by_alias(name).nil?
15
+
16
+ Attribute.new(self,
17
+ ThinkingSphinx::Index::FauxColumn.new(contents),
18
+ :type => type,
19
+ :as => name,
20
+ :facet => facet,
21
+ :admin => true
22
+ )
23
+ end
24
+
25
+ def add_internal_facet(name)
26
+ return unless facet_by_alias(name).nil?
27
+
28
+ @model.sphinx_facets << ClassFacet.new(attribute_by_alias(name))
29
+ end
30
+
31
+ def attribute_by_alias(attr_alias)
32
+ @attributes.detect { |attrib| attrib.alias == attr_alias }
33
+ end
34
+
35
+ def facet_by_alias(name)
36
+ @model.sphinx_facets.detect { |facet| facet.name == name }
37
+ end
38
+
39
+ def subclasses_to_s
40
+ "'" + (@model.send(:subclasses).collect { |klass|
41
+ klass.to_crc32.to_s
42
+ } << @model.to_crc32.to_s).join(",") + "'"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,130 @@
1
+ module ThinkingSphinx
2
+ class Source
3
+ module SQL
4
+ # Generates the big SQL statement to get the data back for all the fields
5
+ # and attributes, using all the relevant association joins. If you want
6
+ # the version filtered for delta values, send through :delta => true in the
7
+ # options. Won't do much though if the index isn't set up to support a
8
+ # delta sibling.
9
+ #
10
+ # Examples:
11
+ #
12
+ # source.to_sql
13
+ # source.to_sql(:delta => true)
14
+ #
15
+ def to_sql(options={})
16
+ sql = "SELECT "
17
+ sql += "SQL_NO_CACHE " if adapter.sphinx_identifier == "mysql"
18
+ sql += <<-SQL
19
+ #{ sql_select_clause options[:offset] }
20
+ FROM #{ @model.quoted_table_name }
21
+ #{ all_associations.collect { |assoc| assoc.to_sql }.join(' ') }
22
+ #{ sql_where_clause(options) }
23
+ GROUP BY #{ sql_group_clause }
24
+ SQL
25
+
26
+ sql += " ORDER BY NULL" if adapter.sphinx_identifier == "mysql"
27
+ sql
28
+ end
29
+
30
+ # Simple helper method for the query range SQL - which is a statement that
31
+ # returns minimum and maximum id values. These can be filtered by delta -
32
+ # so pass in :delta => true to get the delta version of the SQL.
33
+ #
34
+ def to_sql_query_range(options={})
35
+ return nil if @index.options[:disable_range]
36
+
37
+ min_statement = adapter.convert_nulls(
38
+ "MIN(#{quote_column(@model.primary_key_for_sphinx)})", 1
39
+ )
40
+ max_statement = adapter.convert_nulls(
41
+ "MAX(#{quote_column(@model.primary_key_for_sphinx)})", 1
42
+ )
43
+
44
+ sql = "SELECT #{min_statement}, #{max_statement} " +
45
+ "FROM #{@model.quoted_table_name} "
46
+ if self.delta? && !@index.delta_object.clause(@model, options[:delta]).blank?
47
+ sql << "WHERE #{@index.delta_object.clause(@model, options[:delta])}"
48
+ end
49
+
50
+ sql
51
+ end
52
+
53
+ # Simple helper method for the query info SQL - which is a statement that
54
+ # returns the single row for a corresponding id.
55
+ #
56
+ def to_sql_query_info(offset)
57
+ "SELECT * FROM #{@model.quoted_table_name} WHERE " +
58
+ "#{quote_column(@model.primary_key_for_sphinx)} = (($id - #{offset}) / #{ThinkingSphinx.context.indexed_models.size})"
59
+ end
60
+
61
+ def sql_select_clause(offset)
62
+ unique_id_expr = ThinkingSphinx.unique_id_expression(offset)
63
+
64
+ (
65
+ ["#{@model.quoted_table_name}.#{quote_column(@model.primary_key_for_sphinx)} #{unique_id_expr} AS #{quote_column(@model.primary_key_for_sphinx)} "] +
66
+ @fields.collect { |field| field.to_select_sql } +
67
+ @attributes.collect { |attribute| attribute.to_select_sql }
68
+ ).compact.join(", ")
69
+ end
70
+
71
+ def sql_where_clause(options)
72
+ logic = []
73
+ logic += [
74
+ "#{@model.quoted_table_name}.#{quote_column(@model.primary_key_for_sphinx)} >= $start",
75
+ "#{@model.quoted_table_name}.#{quote_column(@model.primary_key_for_sphinx)} <= $end"
76
+ ] unless @index.options[:disable_range]
77
+
78
+ if self.delta? && !@index.delta_object.clause(@model, options[:delta]).blank?
79
+ logic << "#{@index.delta_object.clause(@model, options[:delta])}"
80
+ end
81
+
82
+ logic += (@conditions || [])
83
+ logic.empty? ? "" : "WHERE #{logic.join(' AND ')}"
84
+ end
85
+
86
+ def sql_group_clause
87
+ internal_groupings = []
88
+ if @model.column_names.include?(@model.inheritance_column)
89
+ internal_groupings << "#{@model.quoted_table_name}.#{quote_column(@model.inheritance_column)}"
90
+ end
91
+
92
+ (
93
+ ["#{@model.quoted_table_name}.#{quote_column(@model.primary_key_for_sphinx)}"] +
94
+ @fields.collect { |field| field.to_group_sql }.compact +
95
+ @attributes.collect { |attribute| attribute.to_group_sql }.compact +
96
+ @groupings + internal_groupings
97
+ ).join(", ")
98
+ end
99
+
100
+ def sql_query_pre_for_core
101
+ if self.delta? && !@index.delta_object.reset_query(@model).blank?
102
+ [@index.delta_object.reset_query(@model)]
103
+ else
104
+ []
105
+ end
106
+ end
107
+
108
+ def sql_query_pre_for_delta
109
+ [""]
110
+ end
111
+
112
+ def quote_column(column)
113
+ @model.connection.quote_column_name(column)
114
+ end
115
+
116
+ def crc_column
117
+ if @model.table_exists? &&
118
+ @model.column_names.include?(@model.inheritance_column)
119
+
120
+ adapter.cast_to_unsigned(adapter.convert_nulls(
121
+ adapter.crc(adapter.quote_with_table(@model.inheritance_column), true),
122
+ @model.to_crc32
123
+ ))
124
+ else
125
+ @model.to_crc32.to_s
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,121 @@
1
+ require 'fileutils'
2
+
3
+ namespace :thinking_sphinx do
4
+ task :app_env do
5
+ if defined?(RAILS_ROOT)
6
+ Rake::Task[:environment].invoke
7
+ Rails.configuration.cache_classes = false
8
+ end
9
+
10
+ Rake::Task[:merb_env].invoke if defined?(Merb)
11
+ end
12
+
13
+ desc "Output the current Thinking Sphinx version"
14
+ task :version => :app_env do
15
+ puts "Thinking Sphinx v" + ThinkingSphinx.version
16
+ end
17
+
18
+ desc "Stop if running, then start a Sphinx searchd daemon using Thinking Sphinx's settings"
19
+ task :running_start => :app_env do
20
+ Rake::Task["thinking_sphinx:stop"].invoke if sphinx_running?
21
+ Rake::Task["thinking_sphinx:start"].invoke
22
+ end
23
+
24
+ desc "Start a Sphinx searchd daemon using Thinking Sphinx's settings"
25
+ task :start => :app_env do
26
+ config = ThinkingSphinx::Configuration.instance
27
+
28
+ FileUtils.mkdir_p config.searchd_file_path
29
+ raise RuntimeError, "searchd is already running." if sphinx_running?
30
+
31
+ Dir["#{config.searchd_file_path}/*.spl"].each { |file| File.delete(file) }
32
+
33
+ config.controller.start
34
+
35
+ if sphinx_running?
36
+ puts "Started successfully (pid #{sphinx_pid})."
37
+ else
38
+ puts "Failed to start searchd daemon. Check #{config.searchd_log_file}"
39
+ end
40
+ end
41
+
42
+ desc "Stop Sphinx using Thinking Sphinx's settings"
43
+ task :stop => :app_env do
44
+ unless sphinx_running?
45
+ puts "searchd is not running"
46
+ else
47
+ config = ThinkingSphinx::Configuration.instance
48
+ pid = sphinx_pid
49
+ config.controller.stop
50
+ puts "Stopped search daemon (pid #{pid})."
51
+ end
52
+ end
53
+
54
+ desc "Restart Sphinx"
55
+ task :restart => [:app_env, :stop, :start]
56
+
57
+ desc "Generate the Sphinx configuration file using Thinking Sphinx's settings"
58
+ task :configure => :app_env do
59
+ config = ThinkingSphinx::Configuration.instance
60
+ puts "Generating Configuration to #{config.config_file}"
61
+ config.build
62
+ end
63
+
64
+ desc "Index data for Sphinx using Thinking Sphinx's settings"
65
+ task :index => :app_env do
66
+ config = ThinkingSphinx::Configuration.instance
67
+ unless ENV["INDEX_ONLY"] == "true"
68
+ puts "Generating Configuration to #{config.config_file}"
69
+ config.build
70
+ end
71
+
72
+ FileUtils.mkdir_p config.searchd_file_path
73
+ config.controller.index :verbose => true
74
+ end
75
+
76
+ desc "Reindex Sphinx without regenerating the configuration file"
77
+ task :reindex => :app_env do
78
+ config = ThinkingSphinx::Configuration.instance
79
+ FileUtils.mkdir_p config.searchd_file_path
80
+ puts config.controller.index
81
+ end
82
+
83
+ desc "Stop Sphinx (if it's running), rebuild the indexes, and start Sphinx"
84
+ task :rebuild => :app_env do
85
+ Rake::Task["thinking_sphinx:stop"].invoke if sphinx_running?
86
+ Rake::Task["thinking_sphinx:index"].invoke
87
+ Rake::Task["thinking_sphinx:start"].invoke
88
+ end
89
+ end
90
+
91
+ namespace :ts do
92
+ desc "Output the current Thinking Sphinx version"
93
+ task :version => "thinking_sphinx:version"
94
+ desc "Stop if running, then start a Sphinx searchd daemon using Thinking Sphinx's settings"
95
+ task :run => "thinking_sphinx:running_start"
96
+ desc "Start a Sphinx searchd daemon using Thinking Sphinx's settings"
97
+ task :start => "thinking_sphinx:start"
98
+ desc "Stop Sphinx using Thinking Sphinx's settings"
99
+ task :stop => "thinking_sphinx:stop"
100
+ desc "Index data for Sphinx using Thinking Sphinx's settings"
101
+ task :in => "thinking_sphinx:index"
102
+ task :index => "thinking_sphinx:index"
103
+ desc "Reindex Sphinx without regenerating the configuration file"
104
+ task :reindex => "thinking_sphinx:reindex"
105
+ desc "Restart Sphinx"
106
+ task :restart => "thinking_sphinx:restart"
107
+ desc "Generate the Sphinx configuration file using Thinking Sphinx's settings"
108
+ task :conf => "thinking_sphinx:configure"
109
+ desc "Generate the Sphinx configuration file using Thinking Sphinx's settings"
110
+ task :config => "thinking_sphinx:configure"
111
+ desc "Stop Sphinx (if it's running), rebuild the indexes, and start Sphinx"
112
+ task :rebuild => "thinking_sphinx:rebuild"
113
+ end
114
+
115
+ def sphinx_pid
116
+ ThinkingSphinx.sphinx_pid
117
+ end
118
+
119
+ def sphinx_running?
120
+ ThinkingSphinx.sphinx_running?
121
+ end
@@ -0,0 +1,52 @@
1
+ class ThinkingSphinx::Test
2
+ def self.init(suppress_delta_output = true)
3
+ set_flags suppress_delta_output
4
+ create_indexes_folder
5
+ end
6
+
7
+ def self.start
8
+ config.build
9
+ config.controller.index
10
+ config.controller.start
11
+ end
12
+
13
+ def self.start_with_autostop
14
+ autostop
15
+ start
16
+ end
17
+
18
+ def self.stop
19
+ config.controller.stop
20
+ sleep(0.5) # Ensure Sphinx has shut down completely
21
+ end
22
+
23
+ def self.autostop
24
+ Kernel.at_exit do
25
+ ThinkingSphinx::Test.stop
26
+ end
27
+ end
28
+
29
+ def self.run(&block)
30
+ start
31
+ yield
32
+ stop
33
+ end
34
+
35
+ def self.config
36
+ @config ||= ::ThinkingSphinx::Configuration.instance
37
+ end
38
+
39
+ def self.index(*indexes)
40
+ config.controller.index *indexes
41
+ end
42
+
43
+ def self.set_flags(suppress_delta_output)
44
+ ::ThinkingSphinx.deltas_enabled = true
45
+ ::ThinkingSphinx.updates_enabled = true
46
+ ::ThinkingSphinx.suppress_delta_output = suppress_delta_output
47
+ end
48
+
49
+ def self.create_indexes_folder
50
+ FileUtils.mkdir_p config.searchd_file_path
51
+ end
52
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,16 @@
1
+ Dir[File.join(File.dirname(__FILE__), '../vendor/*/lib')].each do |path|
2
+ $LOAD_PATH.unshift path
3
+ end
4
+
5
+ require 'thinking_sphinx'
6
+ require 'action_controller/dispatcher'
7
+
8
+ ActionController::Dispatcher.to_prepare :thinking_sphinx do
9
+ # Force internationalisation to be loaded.
10
+ if Rails::VERSION::STRING.to_f > 2.2
11
+ I18n.backend.reload!
12
+ I18n.backend.available_locales
13
+ elsif Rails::VERSION::STRING.to_f > 2.1
14
+ I18n.backend.load_translations(*I18n.load_path)
15
+ end
16
+ end
@@ -0,0 +1,128 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe "ThinkingSphinx::ActiveRecord::Delta" do
4
+ it "should call the toggle_delta method after a save" do
5
+ @beta = Beta.new(:name => 'beta')
6
+ @beta.should_receive(:toggle_delta).and_return(true)
7
+
8
+ @beta.save
9
+ end
10
+
11
+ it "should call the toggle_delta method after a save!" do
12
+ @beta = Beta.new(:name => 'beta')
13
+ @beta.should_receive(:toggle_delta).and_return(true)
14
+
15
+ @beta.save!
16
+ end
17
+
18
+ describe "suspended_delta method" do
19
+ before :each do
20
+ ThinkingSphinx.deltas_enabled = true
21
+ Person.sphinx_indexes.first.delta_object.stub!(:` => "")
22
+ end
23
+
24
+ it "should execute the argument block with deltas disabled" do
25
+ ThinkingSphinx.should_receive(:deltas_enabled=).once.with(false)
26
+ ThinkingSphinx.should_receive(:deltas_enabled=).once.with(true)
27
+ lambda { Person.suspended_delta { raise 'i was called' } }.should(
28
+ raise_error(Exception)
29
+ )
30
+ end
31
+
32
+ it "should restore deltas_enabled to its original setting" do
33
+ ThinkingSphinx.deltas_enabled = false
34
+ ThinkingSphinx.should_receive(:deltas_enabled=).twice.with(false)
35
+ Person.suspended_delta { 'no-op' }
36
+ end
37
+
38
+ it "should restore deltas_enabled to its original setting even if there was an exception" do
39
+ ThinkingSphinx.deltas_enabled = false
40
+ ThinkingSphinx.should_receive(:deltas_enabled=).twice.with(false)
41
+ lambda { Person.suspended_delta { raise 'bad error' } }.should(
42
+ raise_error(Exception)
43
+ )
44
+ end
45
+
46
+ it "should reindex by default after the code block is run" do
47
+ Person.should_receive(:index_delta)
48
+ Person.suspended_delta { 'no-op' }
49
+ end
50
+
51
+ it "should not reindex after the code block if false is passed in" do
52
+ Person.should_not_receive(:index_delta)
53
+ Person.suspended_delta(false) { 'no-op' }
54
+ end
55
+ end
56
+
57
+ describe "toggle_delta method" do
58
+ it "should set the delta value to true" do
59
+ @person = Person.new
60
+
61
+ @person.delta.should be_false
62
+ @person.send(:toggle_delta)
63
+ @person.delta.should be_true
64
+ end
65
+ end
66
+
67
+ describe "index_delta method" do
68
+ before :each do
69
+ ThinkingSphinx::Configuration.stub!(:environment => "spec")
70
+ ThinkingSphinx.deltas_enabled = true
71
+ ThinkingSphinx.updates_enabled = true
72
+ ThinkingSphinx.stub!(:sphinx_running? => true)
73
+ Person.delta_object.stub!(:` => "", :toggled => true)
74
+
75
+ @person = Person.new
76
+ Person.stub!(:search_for_id => false)
77
+ @person.stub!(:sphinx_document_id => 1)
78
+
79
+ @client = Riddle::Client.new
80
+ @client.stub!(:update => true)
81
+ ThinkingSphinx::Configuration.instance.stub!(:client => @client)
82
+ end
83
+
84
+ it "shouldn't index if delta indexing is disabled" do
85
+ ThinkingSphinx.deltas_enabled = false
86
+ Person.sphinx_indexes.first.delta_object.should_not_receive(:`)
87
+ @client.should_not_receive(:update)
88
+
89
+ @person.send(:index_delta)
90
+ end
91
+
92
+ it "shouldn't index if index updating is disabled" do
93
+ ThinkingSphinx.updates_enabled = false
94
+ Person.sphinx_indexes.first.delta_object.should_not_receive(:`)
95
+
96
+ @person.send(:index_delta)
97
+ end
98
+
99
+ it "shouldn't index if the environment is 'test'" do
100
+ ThinkingSphinx.deltas_enabled = nil
101
+ ThinkingSphinx::Configuration.stub!(:environment => "test")
102
+ Person.sphinx_indexes.first.delta_object.should_not_receive(:`)
103
+
104
+ @person.send(:index_delta)
105
+ end
106
+
107
+ it "should call indexer for the delta index" do
108
+ Person.sphinx_indexes.first.delta_object.should_receive(:`).with(
109
+ "#{ThinkingSphinx::Configuration.instance.bin_path}indexer --config '#{ThinkingSphinx::Configuration.instance.config_file}' --rotate person_delta"
110
+ )
111
+
112
+ @person.send(:index_delta)
113
+ end
114
+
115
+ it "shouldn't update the deleted attribute if not in the index" do
116
+ @client.should_not_receive(:update)
117
+
118
+ @person.send(:index_delta)
119
+ end
120
+
121
+ it "should update the deleted attribute if in the core index" do
122
+ Person.stub!(:search_for_id => true)
123
+ @client.should_receive(:update)
124
+
125
+ @person.send(:index_delta)
126
+ end
127
+ end
128
+ end