searchgasm 1.2.2 → 1.3.0

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.
Files changed (74) hide show
  1. data/CHANGELOG.rdoc +8 -0
  2. data/Manifest +42 -3
  3. data/README.rdoc +101 -82
  4. data/TODO.rdoc +1 -3
  5. data/lib/searchgasm/active_record/connection_adapters/mysql_adapter.rb +143 -6
  6. data/lib/searchgasm/active_record/connection_adapters/postgresql_adapter.rb +148 -0
  7. data/lib/searchgasm/active_record/connection_adapters/sqlite_adapter.rb +54 -0
  8. data/lib/searchgasm/condition/base.rb +59 -86
  9. data/lib/searchgasm/condition/begins_with.rb +3 -8
  10. data/lib/searchgasm/condition/blank.rb +5 -5
  11. data/lib/searchgasm/condition/ends_with.rb +3 -8
  12. data/lib/searchgasm/condition/equals.rb +4 -3
  13. data/lib/searchgasm/condition/greater_than.rb +3 -14
  14. data/lib/searchgasm/condition/greater_than_or_equal_to.rb +3 -14
  15. data/lib/searchgasm/condition/keywords.rb +3 -8
  16. data/lib/searchgasm/condition/less_than.rb +3 -14
  17. data/lib/searchgasm/condition/less_than_or_equal_to.rb +3 -14
  18. data/lib/searchgasm/condition/like.rb +15 -0
  19. data/lib/searchgasm/condition/nil.rb +5 -5
  20. data/lib/searchgasm/condition/not_begin_with.rb +17 -0
  21. data/lib/searchgasm/condition/not_end_with.rb +17 -0
  22. data/lib/searchgasm/condition/{does_not_equal.rb → not_equal.rb} +5 -4
  23. data/lib/searchgasm/condition/not_have_keywords.rb +17 -0
  24. data/lib/searchgasm/condition/not_like.rb +17 -0
  25. data/lib/searchgasm/condition/tree.rb +4 -5
  26. data/lib/searchgasm/conditions/base.rb +218 -72
  27. data/lib/searchgasm/modifiers/absolute.rb +15 -0
  28. data/lib/searchgasm/modifiers/acos.rb +11 -0
  29. data/lib/searchgasm/modifiers/asin.rb +11 -0
  30. data/lib/searchgasm/modifiers/atan.rb +11 -0
  31. data/lib/searchgasm/modifiers/base.rb +27 -0
  32. data/lib/searchgasm/modifiers/ceil.rb +15 -0
  33. data/lib/searchgasm/modifiers/char_length.rb +15 -0
  34. data/lib/searchgasm/modifiers/cos.rb +15 -0
  35. data/lib/searchgasm/modifiers/cot.rb +15 -0
  36. data/lib/searchgasm/modifiers/day_of_month.rb +15 -0
  37. data/lib/searchgasm/modifiers/day_of_week.rb +15 -0
  38. data/lib/searchgasm/modifiers/day_of_year.rb +15 -0
  39. data/lib/searchgasm/modifiers/degrees.rb +11 -0
  40. data/lib/searchgasm/modifiers/exp.rb +15 -0
  41. data/lib/searchgasm/modifiers/floor.rb +15 -0
  42. data/lib/searchgasm/modifiers/hex.rb +11 -0
  43. data/lib/searchgasm/modifiers/hour.rb +11 -0
  44. data/lib/searchgasm/modifiers/log.rb +15 -0
  45. data/lib/searchgasm/modifiers/log10.rb +11 -0
  46. data/lib/searchgasm/modifiers/log2.rb +11 -0
  47. data/lib/searchgasm/modifiers/md5.rb +11 -0
  48. data/lib/searchgasm/modifiers/microseconds.rb +11 -0
  49. data/lib/searchgasm/modifiers/milliseconds.rb +11 -0
  50. data/lib/searchgasm/modifiers/minute.rb +15 -0
  51. data/lib/searchgasm/modifiers/month.rb +15 -0
  52. data/lib/searchgasm/modifiers/octal.rb +15 -0
  53. data/lib/searchgasm/modifiers/radians.rb +11 -0
  54. data/lib/searchgasm/modifiers/round.rb +11 -0
  55. data/lib/searchgasm/modifiers/second.rb +15 -0
  56. data/lib/searchgasm/modifiers/sign.rb +11 -0
  57. data/lib/searchgasm/modifiers/sin.rb +11 -0
  58. data/lib/searchgasm/modifiers/square_root.rb +15 -0
  59. data/lib/searchgasm/modifiers/tan.rb +15 -0
  60. data/lib/searchgasm/modifiers/week.rb +11 -0
  61. data/lib/searchgasm/modifiers/year.rb +11 -0
  62. data/lib/searchgasm/shared/utilities.rb +0 -10
  63. data/lib/searchgasm/version.rb +2 -2
  64. data/lib/searchgasm.rb +15 -19
  65. data/searchgasm.gemspec +86 -9
  66. data/test/libs/ordered_hash.rb +9 -0
  67. data/test/test_condition_base.rb +21 -47
  68. data/test/test_condition_types.rb +44 -44
  69. data/test/test_conditions_base.rb +34 -21
  70. data/test/test_helper.rb +1 -0
  71. data/test/test_search_conditions.rb +1 -1
  72. metadata +85 -8
  73. data/lib/searchgasm/condition/contains.rb +0 -20
  74. data/lib/searchgasm/condition/during_evening.rb +0 -32
@@ -13,36 +13,51 @@ module Searchgasm
13
13
  class << self
14
14
  attr_accessor :added_klass_conditions, :added_column_conditions, :added_associations
15
15
 
16
- # Registers a condition as an available condition for a column or a class.
16
+ def column_details # :nodoc:
17
+ return @column_details if @column_details
18
+
19
+ @column_details = []
20
+
21
+ klass.columns.each do |column|
22
+ column_detail = {:column => column}
23
+ column_detail[:aliases] = case column.type
24
+ when :datetime, :time, :timestamp
25
+ [column.name.gsub(/_at$/, "")]
26
+ when :date
27
+ [column.name.gsub(/_at$/, "")]
28
+ else
29
+ []
30
+ end
31
+
32
+ @column_details << column_detail
33
+ end
34
+
35
+ @column_details
36
+ end
37
+
38
+ # Registers a condition as an available condition for a column or a class. MySQL supports a "sounds like" function. I want to use it, so let's add it.
17
39
  #
18
40
  # === Example
19
41
  #
20
- # config/initializers/searchgasm.rb
42
+ # # config/initializers/searchgasm.rb
21
43
  # # Actual function for MySQL databases only
22
44
  # class SoundsLike < Searchgasm::Condition::Base
23
- # class << self
24
- # # I pass you the column, you tell me what you want the method to be called.
25
- # # If you don't want to add this condition for that column, return nil
26
- # # It defaults to "#{column.name}_sounds_like" (using the class name). So if thats what you want you don't even need to do this.
27
- # def name_for_column(column)
28
- # super
29
- # end
30
- #
31
- # # Only do this if you want aliases for your condition
32
- # def aliases_for_column(column)
33
- # ["#{column.name}_sounds", "#{column.name}_similar_to"]
34
- # end
45
+ # # The name of the conditions. By default its the name of the class, if you want alternate or alias conditions just add them on.
46
+ # # If you don't want to add aliases you don't even need to define this method
47
+ # def self.name_for_column(column)
48
+ # super
35
49
  # end
36
50
  #
37
51
  # # You can return an array or a string. NOT a hash, because all of these conditions
38
52
  # # need to eventually get merged together. The array or string can be anything you would put in
39
- # # the :conditions option for ActiveRecord::Base.find(). Also, for a list of methods / variables you can use check out earchgasm::Condition::Base
53
+ # # the :conditions option for ActiveRecord::Base.find(). Also notice the column_sql variable. This is essentail
54
+ # # for applying modifiers and should be used in your conditions wherever you want the column.
40
55
  # def to_conditions(value)
41
- # ["#{quoted_table_name}.#{quoted_column_name} SOUNDS LIKE ?", value]
56
+ # ["#{column_sql} SOUNDS LIKE ?", value]
42
57
  # end
43
58
  # end
44
59
  #
45
- # Searchgasm::Seearch::Conditions.register_condition(SoundsLikeCondition)
60
+ # Searchgasm::Seearch::Conditions.register_condition(SoundsLike)
46
61
  def register_condition(condition_class)
47
62
  raise(ArgumentError, "You can only register conditions that extend Searchgasm::Condition::Base") unless condition_class.ancestors.include?(Searchgasm::Condition::Base)
48
63
  conditions << condition_class unless conditions.include?(condition_class)
@@ -53,6 +68,57 @@ module Searchgasm
53
68
  @@conditions ||= []
54
69
  end
55
70
 
71
+ # Registers a modifier as an available modifier for each column.
72
+ #
73
+ # === Example
74
+ #
75
+ # # config/initializers/searchgasm.rb
76
+ # class Ceil < Searchgasm::Modifiers::Base
77
+ # # The name of the modifier. By default its the name of the class, if you want alternate or alias modifiers just add them on.
78
+ # # If you don't want to add aliases you don't even need to define this method
79
+ # def self.modifier_names
80
+ # super + ["round_up"]
81
+ # end
82
+ #
83
+ # # The name of the method in the connection adapters (see below). By default its the name of your class suffixed with "_sql".
84
+ # # So in this example it would be "ceil_sql". Unless you want to change that you don't need to define this method.
85
+ # def self.adapter_method_name
86
+ # super
87
+ # end
88
+ #
89
+ # # This is the type of value returned from the modifier. This is neccessary for typcasting values for the modifier when
90
+ # # applied to a column
91
+ # def self.return_type
92
+ # :integer
93
+ # end
94
+ # end
95
+ #
96
+ # Searchgasm::Seearch::Conditions.register_modifiers(Ceil)
97
+ #
98
+ # Now here's the fun part, applying this modifier to each connection adapter. Some databases call modifiers differently. If they all apply them the same you can
99
+ # add in the function to ActiveRecord::ConnectionAdapters::AbstractAdapter, otherwise you need to add them to each
100
+ # individually: ActiveRecord::ConnectionAdapters::MysqlAdapter, ActiveRecord::ConnectionAdapters::PostgreSQLAdapter, ActiveRecord::ConnectionAdapters::SQLiteAdapter
101
+ #
102
+ # Do this by includine a model with your method. The name of your method, by default, is: #{modifier_name}_sql. So in the example above it would be "ceil_sql"
103
+ #
104
+ # module CeilAdapterMethod
105
+ # def ceil_sql(column_name)
106
+ # "CEIL(#{column_name})"
107
+ # end
108
+ # end
109
+ #
110
+ # ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:include, CeilAdapterMethod)
111
+ # # ... include for the rest of the adapters
112
+ def register_modifier(modifier_class)
113
+ raise(ArgumentError, "You can only register conditions that extend Searchgasm::Modifiers::Base") unless modifier_class.ancestors.include?(Searchgasm::Modifiers::Base)
114
+ modifiers << modifier_class unless modifiers.include?(modifier_class)
115
+ end
116
+
117
+ # A list of available modifier classes
118
+ def modifiers
119
+ @@modifiers ||= []
120
+ end
121
+
56
122
  # A list of all associations created, used for caching and performance
57
123
  def association_names
58
124
  @association_names ||= []
@@ -82,8 +148,6 @@ module Searchgasm
82
148
  end
83
149
 
84
150
  def initialize(init_conditions = {})
85
- add_klass_conditions!
86
- add_column_conditions!
87
151
  add_associations!
88
152
  self.conditions = init_conditions
89
153
  end
@@ -95,7 +159,7 @@ module Searchgasm
95
159
  # search.conditions.any = true # will join all conditions with "or", you can also set this to "true", "1", or "yes"
96
160
  # search.conditions.any = false # will join all conditions with "and"
97
161
  def any=(value)
98
- associations.each { |association| association.any = value }
162
+ associations.each { |name, association| association.any = value }
99
163
  @any = value
100
164
  end
101
165
 
@@ -111,7 +175,7 @@ module Searchgasm
111
175
  # A list of joins to use when searching, includes relationships
112
176
  def auto_joins
113
177
  j = []
114
- associations.each do |association|
178
+ associations.each do |name, association|
115
179
  next if association.conditions.blank?
116
180
  association_joins = association.auto_joins
117
181
  j << (association_joins.blank? ? association.relationship_name.to_sym : {association.relationship_name.to_sym => association_joins})
@@ -126,16 +190,15 @@ module Searchgasm
126
190
  # Sanitizes the conditions down into conditions that ActiveRecord::Base.find can understand.
127
191
  def sanitize
128
192
  return @conditions if @conditions
129
- merge_conditions(*(objects.collect { |object| object.sanitize } << {:any => any}))
193
+ merge_conditions(*(objects.collect { |name, object| object.sanitize } << {:any => any}))
130
194
  end
131
195
 
132
196
  # Allows you to set the conditions via a hash.
133
197
  def conditions=(value)
134
198
  case value
135
- when Hash
199
+ when Hash
136
200
  assert_valid_conditions(value)
137
201
  remove_conditions_from_protected_assignement(value).each do |condition, condition_value|
138
- next if meaningless?(condition_value) # ignore blanks on mass assignments
139
202
  send("#{condition}=", condition_value)
140
203
  end
141
204
  else
@@ -150,14 +213,14 @@ module Searchgasm
150
213
  return if objects.blank?
151
214
 
152
215
  conditions_hash = {}
153
- objects.each do |object|
216
+ objects.each do |name, object|
154
217
  if object.class < Searchgasm::Conditions::Base
155
218
  relationship_conditions = object.conditions
156
219
  next if relationship_conditions.blank?
157
220
  conditions_hash[object.relationship_name.to_sym] = relationship_conditions
158
221
  else
159
- next unless object.explicitly_set_value?
160
- conditions_hash[object.name.to_sym] = object.value
222
+ next if object.meaningless_value?
223
+ conditions_hash[name] = object.value
161
224
  end
162
225
  end
163
226
  conditions_hash
@@ -172,62 +235,150 @@ module Searchgasm
172
235
 
173
236
  self.class.class_eval <<-"end_eval", __FILE__, __LINE__
174
237
  def #{association.name}
175
- if @#{association.name}.nil?
176
- @#{association.name} = Searchgasm::Conditions::Base.create_virtual_class(#{association.class_name}).new
177
- @#{association.name}.relationship_name = "#{association.name}"
178
- @#{association.name}.protect = protect
179
- objects << @#{association.name}
238
+ if objects[:#{association.name}].nil?
239
+ objects[:#{association.name}] = Searchgasm::Conditions::Base.create_virtual_class(#{association.class_name}).new
240
+ objects[:#{association.name}].relationship_name = "#{association.name}"
241
+ objects[:#{association.name}].protect = protect
180
242
  end
181
- @#{association.name}
243
+ objects[:#{association.name}]
182
244
  end
183
245
 
184
246
  def #{association.name}=(conditions); @conditions = nil; #{association.name}.conditions = conditions; end
185
- def reset_#{association.name}!; objects.delete(#{association.name}); @#{association.name} = nil; end
247
+ def reset_#{association.name}!; objects.delete(:#{association.name}); end
186
248
  end_eval
187
249
  end
188
250
 
189
251
  self.class.added_associations = true
190
252
  end
191
253
 
192
- def add_column_conditions!
193
- return true if self.class.added_column_conditions
254
+ def extract_column_and_condition_from_method_name(name)
255
+ name_parts = name.gsub("=", "").split("_")
194
256
 
195
- klass.columns.each do |column|
196
- self.class.conditions.each do |condition_klass|
197
- name = condition_klass.name_for_column(column)
198
- next if name.blank?
199
- add_condition!(condition_klass, name, column)
200
- condition_klass.aliases_for_column(column).each { |alias_name| add_condition_alias!(alias_name, name) }
257
+ condition_parts = []
258
+ column = nil
259
+ while column.nil? && name_parts.size > 0
260
+ possible_column_name = name_parts.join("_")
261
+
262
+ self.class.column_details.each do |column_detail|
263
+ if column_detail[:column].name == possible_column_name || column_detail[:aliases].include?(possible_column_name)
264
+ column = column_detail
265
+ break
266
+ end
201
267
  end
268
+
269
+ condition_parts << name_parts.pop if !column
202
270
  end
203
271
 
204
- self.class.added_column_conditions = true
272
+ return if column.nil?
273
+
274
+ condition_name = condition_parts.reverse.join("_")
275
+ condition = nil
276
+
277
+ # Find the real condition
278
+ self.class.conditions.each do |condition_klass|
279
+ if condition_klass.condition_names_for_column.include?(condition_name)
280
+ condition = condition_klass
281
+ break
282
+ end
283
+ end
284
+
285
+ [column, condition]
205
286
  end
206
287
 
207
- def add_condition!(condition, name, column = nil)
288
+ def breakdown_method_name(name)
289
+ column_detail, condition_klass = extract_column_and_condition_from_method_name(name)
290
+ if !column_detail.nil? && !condition_klass.nil?
291
+ # There were no modifiers
292
+ return [[], column_detail, condition_klass]
293
+ else
294
+ # There might be modifiers
295
+ name_parts = name.split("_of_")
296
+ column_detail, condition_klass = extract_column_and_condition_from_method_name(name_parts.pop)
297
+ if !column_detail.nil? && !condition_klass.nil?
298
+ # There were modifiers, lets get their real names
299
+ modifier_klasses = []
300
+ name_parts.each do |modifier_name|
301
+ size_before = modifier_klasses.size
302
+ self.class.modifiers.each do |modifier_klass|
303
+ if modifier_klass.modifier_names.include?(modifier_name)
304
+ modifier_klasses << modifier_klass
305
+ break
306
+ end
307
+ end
308
+ return if modifier_klasses.size == size_before # there was an invalid modifer, return nil for everything and let it act as a nomethoderror
309
+ end
310
+
311
+ return [modifier_klasses, column_detail, condition_klass]
312
+ end
313
+ end
314
+
315
+ nil
316
+ end
317
+
318
+ def build_method_name(modifier_klasses, column_name, condition_name)
319
+ modifier_name_parts = []
320
+ modifier_klasses.each { |modifier_klass| modifier_name_parts << modifier_klass.modifier_names.first }
321
+ method_name_parts = []
322
+ method_name_parts << modifier_name_parts.join("_of_") unless modifier_name_parts.blank?
323
+ method_name_parts << column_name
324
+ method_name_parts << condition_name
325
+ method_name_parts.join("_")
326
+ end
327
+
328
+ def method_missing(name, *args, &block)
329
+ modifier_klasses, column_detail, condition_klass = breakdown_method_name(name.to_s)
330
+ if !column_detail.nil? && !condition_klass.nil?
331
+ method_name = build_method_name(modifier_klasses, column_detail[:column].name, condition_klass.condition_names_for_column.first)
332
+ column_type = column_sql = nil
333
+ if !modifier_klasses.blank?
334
+ # Find the column type
335
+ column_type = modifier_klasses.first.return_type
336
+
337
+ # Build the column sql
338
+ column_sql = "#{klass.connection.quote_table_name(klass.table_name)}.#{klass.connection.quote_column_name(column_detail[:column].name)}"
339
+ modifier_klasses.each do |modifier_klass|
340
+ next unless klass.connection.respond_to?(modifier_klass.adapter_method_name)
341
+ column_sql = klass.connection.send(modifier_klass.adapter_method_name, column_sql)
342
+ end
343
+ end
344
+
345
+ add_condition!(condition_klass, method_name, column_detail[:column], column_type, column_sql)
346
+
347
+ ([column_detail[:column].name] + column_detail[:aliases]).each do |column_name|
348
+ condition_klass.condition_names_for_column.each do |condition_name|
349
+ alias_method_name = build_method_name(modifier_klasses, column_name, condition_name)
350
+ add_condition_alias!(alias_method_name, method_name) unless alias_method_name == method_name
351
+ end
352
+ end
353
+
354
+ send(method_name + (name.to_s =~ /=$/ ? "=" : ""), *args, &block)
355
+ else
356
+ super
357
+ end
358
+ end
359
+
360
+ def add_condition!(condition, name, column = nil, column_type = nil, column_sql = nil)
208
361
  self.class.condition_names << name
209
362
 
210
363
  self.class.class_eval <<-"end_eval", __FILE__, __LINE__
211
364
  def #{name}_object
212
- if @#{name}.nil?
213
- @#{name} = #{condition.name}.new(klass#{column.nil? ? "" : ", \"#{column.name}\""})
214
- objects << @#{name}
365
+ if objects[:#{name}].nil?
366
+ objects[:#{name}] = #{condition.name}.new(klass, #{column.blank? ? "nil" : "klass.columns_hash['#{column.name}']"}, #{column_type.blank? ? "nil" : "\"#{column_type}\""}, #{column_sql.blank? ? "nil" : "\"#{column_sql.gsub('"', '\"')}\""})
215
367
  end
216
- @#{name}
368
+ objects[:#{name}]
217
369
  end
218
370
 
219
371
  def #{name}; #{name}_object.value; end
220
372
 
221
373
  def #{name}=(value)
222
- if meaningless?(value) && #{name}_object.class.ignore_meaningless?
223
- reset_#{name}!
224
- else
225
- @conditions = nil
226
- #{name}_object.value = value
227
- end
374
+ @conditions = nil
375
+
376
+ #{name}_object.value = value
377
+ reset_#{name}! if #{name}_object.meaningless_value?
378
+ value
228
379
  end
229
380
 
230
- def reset_#{name}!; objects.delete(#{name}_object); @#{name} = nil; end
381
+ def reset_#{name}!; objects.delete(:#{name}); end
231
382
  end_eval
232
383
  end
233
384
 
@@ -235,38 +386,33 @@ module Searchgasm
235
386
  self.class.condition_names << alias_name
236
387
 
237
388
  self.class.class_eval do
389
+ alias_method "#{alias_name}_object", "#{name}_object"
238
390
  alias_method alias_name, name
239
391
  alias_method "#{alias_name}=", "#{name}="
392
+ alias_method "reset_#{alias_name}!", "reset_#{name}!"
240
393
  end
241
394
  end
242
395
 
243
- def add_klass_conditions!
244
- return true if self.class.added_klass_conditions
245
-
246
- self.class.conditions.each do |condition|
247
- name = condition.name_for_klass(klass)
248
- next if name.blank?
249
- add_condition!(condition, name)
250
- condition.aliases_for_klass(klass).each { |alias_name| add_condition_alias!(alias_name, name) }
251
- end
252
-
253
- self.class.added_klass_conditions = true
254
- end
255
-
256
396
  def assert_valid_conditions(conditions)
257
- conditions.stringify_keys.fast_assert_valid_keys(self.class.condition_names + self.class.association_names + ["any"])
397
+ conditions.each do |condition, value|
398
+ raise(ArgumentError, "The #{condition} condition is not a valid condition") if !(self.class.condition_names + self.class.association_names + ["any"]).include?(condition.to_s) && respond_to?(condition)
399
+ end
258
400
  end
259
401
 
260
402
  def associations
261
- objects.select { |object| object.class < ::Searchgasm::Conditions::Base }
403
+ associations = {}
404
+ objects.each do |name, object|
405
+ associations[name] = object if object.class < ::Searchgasm::Conditions::Base
406
+ end
407
+ associations
262
408
  end
263
409
 
264
410
  def objects
265
- @objects ||= []
411
+ @objects ||= {}
266
412
  end
267
413
 
268
414
  def reset_objects!
269
- objects.each { |object| object.class < ::Searchgasm::Conditions::Base ? eval("@#{object.relationship_name} = nil") : eval("@#{object.name} = nil") }
415
+ objects.each { |name, object| object.class < ::Searchgasm::Conditions::Base ? eval("@#{object.relationship_name} = nil") : eval("@#{name} = nil") }
270
416
  objects.clear
271
417
  end
272
418
 
@@ -0,0 +1,15 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Absolute < Base
4
+ class << self
5
+ def modifier_names
6
+ super + ["abs"]
7
+ end
8
+
9
+ def return_type
10
+ :integer
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Acos < Base
4
+ class << self
5
+ def return_type
6
+ :float
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Asin < Base
4
+ class << self
5
+ def return_type
6
+ :float
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Atan < Base
4
+ class << self
5
+ def return_type
6
+ :float
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,27 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Base
4
+ class << self
5
+ # A convenience method for the name of this modifier
6
+ def modifier_name
7
+ name.split("::").last.underscore
8
+ end
9
+
10
+ # The various names for the modifier. The first in the array is the "main" name, the rest are just aliases to the "main" name
11
+ def modifier_names
12
+ [modifier_name]
13
+ end
14
+
15
+ # The method in the connection adapter that creates the SQL for the modifier
16
+ def adapter_method_name
17
+ "#{modifier_name}_sql"
18
+ end
19
+
20
+ # The type of value returned from the SQL. A class the extends this MUST define this method.
21
+ def return_type
22
+ raise "You did not specify a return type for the #{modifier_name} modifier. Please specify if it is an :integer, :string, etc."
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Ceil < Base
4
+ class << self
5
+ def modifier_names
6
+ super + ["round_up"]
7
+ end
8
+
9
+ def return_type
10
+ :integer
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class CharLength < Base
4
+ class << self
5
+ def modifier_names
6
+ super + ["length"]
7
+ end
8
+
9
+ def return_type
10
+ :integer
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Cos < Base
4
+ class << self
5
+ def modifier_names
6
+ super + ["cosine"]
7
+ end
8
+
9
+ def return_type
10
+ :float
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Cot < Base
4
+ class << self
5
+ def modifier_names
6
+ super + ["cotangent"]
7
+ end
8
+
9
+ def return_type
10
+ :float
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class DayOfMonth < Base
4
+ class << self
5
+ def modifier_names
6
+ super + ["dom"]
7
+ end
8
+
9
+ def return_type
10
+ :integer
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class DayOfWeek < Base
4
+ class << self
5
+ def modifier_names
6
+ super + ["dow"]
7
+ end
8
+
9
+ def return_type
10
+ :integer
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class DayOfYear < Base
4
+ class << self
5
+ def modifier_names
6
+ super + ["doy"]
7
+ end
8
+
9
+ def return_type
10
+ :integer
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Degrees < Base
4
+ class << self
5
+ def return_type
6
+ :float
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Exp < Base
4
+ class << self
5
+ def modifier_names
6
+ super + ["exponential"]
7
+ end
8
+
9
+ def return_type
10
+ :float
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Floor < Base
4
+ class << self
5
+ def modifier_names
6
+ super + ["round_down"]
7
+ end
8
+
9
+ def return_type
10
+ :integer
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Hex < Base
4
+ class << self
5
+ def return_type
6
+ :string
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end