freelancing-god-thinking-sphinx 1.1.1 → 1.1.2

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.
data/README CHANGED
@@ -94,3 +94,8 @@ Since I first released this library, there's been quite a few people who have su
94
94
  - Henrik Nyh
95
95
  - Emil Tin
96
96
  - Doug Cole
97
+ - Ed Hickey
98
+ - Evan Weaver
99
+ - Thibaut Barrere
100
+ - Kristopher Chambers
101
+ - Dmitrij Smalko
@@ -31,7 +31,7 @@ module ThinkingSphinx
31
31
  module Version #:nodoc:
32
32
  Major = 1
33
33
  Minor = 1
34
- Tiny = 1
34
+ Tiny = 2
35
35
 
36
36
  String = [Major, Minor, Tiny].join('.')
37
37
  end
@@ -131,13 +131,11 @@ module ThinkingSphinx
131
131
  end
132
132
 
133
133
  def self.sphinx_running?
134
- pid_file = ThinkingSphinx::Configuration.instance.pid_file
135
-
136
- if pid_file && File.exists?(pid_file)
137
- pid = `cat #{pid_file}`[/\d+/]
138
- `ps -p #{pid} | wc -l`.to_i > 1
139
- else
140
- false
141
- end
134
+ !!sphinx_pid
135
+ end
136
+
137
+ def self.sphinx_pid
138
+ pid_file = ThinkingSphinx::Configuration.instance.pid_file
139
+ `cat #{pid_file}`[/\d+/] if File.exists?(pid_file)
142
140
  end
143
141
  end
@@ -42,7 +42,11 @@ module ThinkingSphinx
42
42
  # if running in the test environment.
43
43
  #
44
44
  def index_delta(instance = nil)
45
- self.sphinx_indexes.first.delta_object.index(self, instance)
45
+ delta_object.index(self, instance)
46
+ end
47
+
48
+ def delta_object
49
+ self.sphinx_indexes.first.delta_object
46
50
  end
47
51
  end
48
52
 
@@ -50,14 +54,18 @@ module ThinkingSphinx
50
54
 
51
55
  # Set the delta value for the model to be true.
52
56
  def toggle_delta
53
- self.class.sphinx_indexes.first.delta_object.toggle(self)
57
+ self.class.delta_object.toggle(self) if should_toggle_delta?
54
58
  end
55
59
 
56
60
  # Build the delta index for the related model. This won't be called
57
61
  # if running in the test environment.
58
62
  #
59
63
  def index_delta
60
- self.class.index_delta(self)
64
+ self.class.index_delta(self) if self.class.delta_object.toggled(self)
65
+ end
66
+
67
+ def should_toggle_delta?
68
+ !self.respond_to?(:changed?) || self.changed? || self.new_record?
61
69
  end
62
70
  end
63
71
  end
@@ -175,7 +175,7 @@ module ThinkingSphinx
175
175
  when "ActiveRecord::ConnectionAdapters::MysqlAdapter"
176
176
  "UNIX_TIMESTAMP(#{clause})"
177
177
  when "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter"
178
- clause # Rails' datetimes are timestamps in PostgreSQL
178
+ "cast(extract(epoch from #{clause}) as int)"
179
179
  else
180
180
  clause
181
181
  end
@@ -263,11 +263,7 @@ module ThinkingSphinx
263
263
  when @associations.values.flatten.length > 1
264
264
  :string
265
265
  else
266
- klass = @associations.values.flatten.first ?
267
- @associations.values.flatten.first.reflection.klass : @model
268
- klass.columns.detect { |col|
269
- @columns.collect { |c| c.__name.to_s }.include? col.name
270
- }.type
266
+ translated_type_from_database
271
267
  end
272
268
  end
273
269
 
@@ -281,5 +277,33 @@ module ThinkingSphinx
281
277
  }
282
278
  }
283
279
  end
280
+
281
+ def type_from_database
282
+ klass = @associations.values.flatten.first ?
283
+ @associations.values.flatten.first.reflection.klass : @model
284
+
285
+ klass.columns.detect { |col|
286
+ @columns.collect { |c| c.__name.to_s }.include? col.name
287
+ }.type
288
+ end
289
+
290
+ def translated_type_from_database
291
+ case type_from_db = type_from_database
292
+ when :datetime, :string, :float, :boolean, :integer
293
+ type_from_db
294
+ when :decimal
295
+ :float
296
+ when :timestamp, :date
297
+ :datetime
298
+ else
299
+ raise <<-MESSAGE
300
+
301
+ Cannot automatically map column type #{type_from_db} to an equivalent Sphinx
302
+ type (integer, float, boolean, datetime, string as ordinal). You could try to
303
+ explicitly convert the column's value in your define_index block:
304
+ has "CAST(column AS INT)", :type => :integer, :as => :column
305
+ MESSAGE
306
+ end
307
+ end
284
308
  end
285
309
  end
@@ -55,7 +55,7 @@ module ThinkingSphinx
55
55
 
56
56
  attr_accessor :config_file, :searchd_log_file, :query_log_file,
57
57
  :pid_file, :searchd_file_path, :address, :port, :allow_star,
58
- :database_yml_file, :app_root, :bin_path
58
+ :database_yml_file, :app_root, :bin_path, :model_directories
59
59
 
60
60
  attr_accessor :source_options, :index_options
61
61
 
@@ -85,6 +85,7 @@ module ThinkingSphinx
85
85
  self.searchd_file_path = "#{self.app_root}/db/sphinx/#{environment}"
86
86
  self.allow_star = false
87
87
  self.bin_path = ""
88
+ self.model_directories = ["#{app_root}/app/models/"]
88
89
 
89
90
  self.source_options = {}
90
91
  self.index_options = {
@@ -135,21 +136,22 @@ module ThinkingSphinx
135
136
  # messy dependencies issues).
136
137
  #
137
138
  def load_models
138
- base = "#{app_root}/app/models/"
139
- Dir["#{base}**/*.rb"].each do |file|
140
- model_name = file.gsub(/^#{base}([\w_\/\\]+)\.rb/, '\1')
139
+ self.model_directories.each do |base|
140
+ Dir["#{base}**/*.rb"].each do |file|
141
+ model_name = file.gsub(/^#{base}([\w_\/\\]+)\.rb/, '\1')
141
142
 
142
- next if model_name.nil?
143
- next if ::ActiveRecord::Base.send(:subclasses).detect { |model|
144
- model.name == model_name
145
- }
143
+ next if model_name.nil?
144
+ next if ::ActiveRecord::Base.send(:subclasses).detect { |model|
145
+ model.name == model_name
146
+ }
146
147
 
147
- begin
148
- model_name.camelize.constantize
149
- rescue LoadError
150
- model_name.gsub!(/.*[\/\\]/, '').nil? ? next : retry
151
- rescue NameError
152
- next
148
+ begin
149
+ model_name.camelize.constantize
150
+ rescue LoadError
151
+ model_name.gsub!(/.*[\/\\]/, '').nil? ? next : retry
152
+ rescue NameError
153
+ next
154
+ end
153
155
  end
154
156
  end
155
157
  end
@@ -240,6 +242,11 @@ module ThinkingSphinx
240
242
  end unless conf.nil?
241
243
 
242
244
  self.bin_path += '/' unless self.bin_path.blank?
245
+
246
+ if self.allow_star
247
+ self.index_options[:enable_star] = true
248
+ self.index_options[:min_prefix_len] = 1
249
+ end
243
250
  end
244
251
 
245
252
  def set_sphinx_setting(object, key, value, allowed = {})
@@ -1,5 +1,6 @@
1
1
  require 'thinking_sphinx/deltas/default_delta'
2
2
  require 'thinking_sphinx/deltas/delayed_delta'
3
+ require 'thinking_sphinx/deltas/datetime_delta'
3
4
 
4
5
  module ThinkingSphinx
5
6
  module Deltas
@@ -9,6 +10,8 @@ module ThinkingSphinx
9
10
  DefaultDelta.new index, options
10
11
  when :delayed
11
12
  DelayedDelta.new index, options
13
+ when :datetime
14
+ DatetimeDelta.new index, options
12
15
  when FalseClass, nil
13
16
  nil
14
17
  else
@@ -0,0 +1,61 @@
1
+ module ThinkingSphinx
2
+ module Deltas
3
+ class DatetimeDelta < ThinkingSphinx::Deltas::DefaultDelta
4
+ attr_accessor :column, :threshold
5
+
6
+ def initialize(index, options)
7
+ @index = index
8
+ @column = options.delete(:delta_column) || :updated_at
9
+ @threshold = options.delete(:threshold) || 1.day
10
+ end
11
+
12
+ def index(model, instance = nil)
13
+ # do nothing
14
+ true
15
+ end
16
+
17
+ def delayed_index(model)
18
+ config = ThinkingSphinx::Configuration.instance
19
+ rotate = ThinkingSphinx.sphinx_running? ? "--rotate" : ""
20
+
21
+ output = `#{config.bin_path}indexer --config #{config.config_file} #{rotate} #{delta_index_name model}`
22
+ output += `#{config.bin_path}indexer --config #{config.config_file} #{rotate} --merge #{core_index_name model} #{delta_index_name model} --merge-dst-range sphinx_deleted 0 0`
23
+ puts output unless ThinkingSphinx.suppress_delta_output?
24
+
25
+ true
26
+ end
27
+
28
+ def toggle(instance)
29
+ # do nothing
30
+ end
31
+
32
+ def toggled(instance)
33
+ instance.send(@column) > @threshold.ago
34
+ end
35
+
36
+ def reset_query(model)
37
+ nil
38
+ end
39
+
40
+ def clause(model, toggled)
41
+ if toggled
42
+ "#{model.quoted_table_name}.#{@index.quote_column(@column.to_s)}" +
43
+ " > #{time_difference}"
44
+ else
45
+ nil
46
+ end
47
+ end
48
+
49
+ def time_difference
50
+ case @index.adapter
51
+ when :mysql
52
+ "DATE_SUB(NOW(), INTERVAL #{@threshold} SECOND)"
53
+ when :postgres
54
+ "current_timestamp - interval '#{@threshold} seconds'"
55
+ else
56
+ raise "Unknown Database Adapter"
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -5,7 +5,7 @@ module ThinkingSphinx
5
5
 
6
6
  def initialize(index, options)
7
7
  @index = index
8
- @column = options.delete(:column) || :delta
8
+ @column = options.delete(:delta_column) || :delta
9
9
  end
10
10
 
11
11
  def index(model, instance = nil)
@@ -31,6 +31,15 @@ module ThinkingSphinx
31
31
  instance.delta = true
32
32
  end
33
33
 
34
+ def toggled(instance)
35
+ instance.delta
36
+ end
37
+
38
+ def reset_query(model)
39
+ "UPDATE #{model.quoted_table_name} SET " +
40
+ "#{@index.quote_column(@column.to_s)} = #{@index.db_boolean(false)}"
41
+ end
42
+
34
43
  def clause(model, toggled)
35
44
  "#{model.quoted_table_name}.#{@index.quote_column(@column.to_s)}" +
36
45
  " = #{@index.db_boolean(toggled)}"
@@ -44,7 +53,7 @@ module ThinkingSphinx
44
53
 
45
54
  def delta_index_name(model)
46
55
  "#{model.source_of_sphinx_index.name.underscore.tr(':/\\', '_')}_delta"
47
- end
56
+ end
48
57
  end
49
58
  end
50
59
  end
@@ -126,7 +126,7 @@ module ThinkingSphinx
126
126
  assocs = all_associations
127
127
 
128
128
  where_clause = ""
129
- if self.delta?
129
+ if self.delta? && !@delta_object.clause(@model, options[:delta]).blank?
130
130
  where_clause << " AND #{@delta_object.clause(@model, options[:delta])}"
131
131
  end
132
132
  unless @conditions.empty?
@@ -190,7 +190,10 @@ GROUP BY #{ (
190
190
 
191
191
  sql = "SELECT #{min_statement}, #{max_statement} " +
192
192
  "FROM #{@model.quoted_table_name} "
193
- sql << "WHERE #{@delta_object.clause(@model, options[:delta])}" if self.delta?
193
+ if self.delta? && !@delta_object.clause(@model, options[:delta]).blank?
194
+ sql << "WHERE #{@delta_object.clause(@model, options[:delta])}"
195
+ end
196
+
194
197
  sql
195
198
  end
196
199
 
@@ -436,8 +439,8 @@ GROUP BY #{ (
436
439
  end
437
440
 
438
441
  def sql_query_pre_for_core
439
- if self.delta?
440
- ["UPDATE #{@model.quoted_table_name} SET #{@delta_object.clause(@model, false)}"]
442
+ if self.delta? && !@delta_object.reset_query(@model).blank?
443
+ [@delta_object.reset_query(@model)]
441
444
  else
442
445
  []
443
446
  end
@@ -29,6 +29,18 @@ Array.send(
29
29
  :include, ThinkingSphinx::ArrayExtractOptions
30
30
  ) unless Array.instance_methods.include?("extract_options!")
31
31
 
32
+ module ThinkingSphinx
33
+ module AbstractQuotedTableName
34
+ def quote_table_name(name)
35
+ quote_column_name(name)
36
+ end
37
+ end
38
+ end
39
+
40
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.send(
41
+ :include, ThinkingSphinx::AbstractQuotedTableName
42
+ ) unless ActiveRecord::ConnectionAdapters::AbstractAdapter.instance_methods.include?("quote_table_name")
43
+
32
44
  module ThinkingSphinx
33
45
  module MysqlQuotedTableName
34
46
  def quote_table_name(name) #:nodoc:
@@ -72,7 +72,7 @@ describe "ThinkingSphinx::ActiveRecord::Delta" do
72
72
  before :each do
73
73
  ThinkingSphinx::Configuration.stub_method(:environment => "spec")
74
74
  ThinkingSphinx.stub_method(:deltas_enabled? => true, :sphinx_running? => true)
75
- Person.sphinx_indexes.first.delta_object.stub_method(:` => "")
75
+ Person.delta_object.stub_methods(:` => "", :toggled => true)
76
76
 
77
77
  @person = Person.new
78
78
  @person.stub_method(
@@ -37,8 +37,9 @@ namespace :thinking_sphinx do
37
37
  desc "Stop Sphinx using Thinking Sphinx's settings"
38
38
  task :stop => :app_env do
39
39
  raise RuntimeError, "searchd is not running." unless sphinx_running?
40
- pid = sphinx_pid
41
- system "kill #{pid}"
40
+ config = ThinkingSphinx::Configuration.instance
41
+ pid = sphinx_pid
42
+ system "searchd --stop --config #{config.config_file}"
42
43
  puts "Stopped search daemon (pid #{pid})."
43
44
  end
44
45
 
@@ -69,8 +70,22 @@ namespace :thinking_sphinx do
69
70
  system cmd
70
71
  end
71
72
 
73
+ namespace :index do
74
+ task :delta => :app_env do
75
+ ThinkingSphinx.indexed_models.select { |model|
76
+ model.constantize.sphinx_indexes.any? { |index| index.delta? }
77
+ }.each do |model|
78
+ model.constantize.sphinx_indexes.select { |index|
79
+ index.delta? && index.delta_object.respond_to?(:delayed_index)
80
+ }.each { |index|
81
+ index.delta_object.delayed_index(index.model)
82
+ }
83
+ end
84
+ end
85
+ end
86
+
72
87
  desc "Process stored delta index requests"
73
- task :delta => :app_env do
88
+ task :delayed_delta => :app_env do
74
89
  require 'delayed/worker'
75
90
 
76
91
  Delayed::Worker.new(
@@ -90,6 +105,9 @@ namespace :ts do
90
105
  desc "Index data for Sphinx using Thinking Sphinx's settings"
91
106
  task :in => "thinking_sphinx:index"
92
107
  desc "Index data for Sphinx using Thinking Sphinx's settings"
108
+ namespace :in do
109
+ task :delta => "thinking_sphinx:index:delta"
110
+ end
93
111
  task :index => "thinking_sphinx:index"
94
112
  desc "Restart Sphinx"
95
113
  task :restart => "thinking_sphinx:restart"
@@ -98,19 +116,13 @@ namespace :ts do
98
116
  desc "Generate the Sphinx configuration file using Thinking Sphinx's settings"
99
117
  task :config => "thinking_sphinx:configure"
100
118
  desc "Process stored delta index requests"
101
- task :delta => "thinking_sphinx:delta"
119
+ task :dd => "thinking_sphinx:delayed_delta"
102
120
  end
103
121
 
104
122
  def sphinx_pid
105
- config = ThinkingSphinx::Configuration.instance
106
-
107
- if File.exists?(config.pid_file)
108
- `cat #{config.pid_file}`[/\d+/]
109
- else
110
- nil
111
- end
123
+ ThinkingSphinx.sphinx_pid
112
124
  end
113
125
 
114
126
  def sphinx_running?
115
- sphinx_pid && `ps -p #{sphinx_pid} | wc -l`.to_i > 1
127
+ ThinkingSphinx.sphinx_running?
116
128
  end
@@ -10,7 +10,7 @@ module Riddle
10
10
  cmd << " --rotate" if running?
11
11
  `#{cmd}`
12
12
  end
13
-
13
+
14
14
  def start
15
15
  return if running?
16
16
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: freelancing-god-thinking-sphinx
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pat Allan
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-01-03 00:00:00 -08:00
12
+ date: 2009-01-08 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -33,6 +33,7 @@ files:
33
33
  - lib/thinking_sphinx/attribute.rb
34
34
  - lib/thinking_sphinx/collection.rb
35
35
  - lib/thinking_sphinx/configuration.rb
36
+ - lib/thinking_sphinx/deltas/datetime_delta.rb
36
37
  - lib/thinking_sphinx/deltas/default_delta.rb
37
38
  - lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb
38
39
  - lib/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job.rb