searchgasm 1.3.5 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/CHANGELOG.rdoc +11 -0
  2. data/Manifest +12 -3
  3. data/README.rdoc +11 -0
  4. data/TODO.rdoc +4 -1
  5. data/lib/searchgasm/active_record/associations.rb +25 -14
  6. data/lib/searchgasm/active_record/base.rb +49 -0
  7. data/lib/searchgasm/active_record/connection_adapters/mysql_adapter.rb +20 -0
  8. data/lib/searchgasm/active_record/connection_adapters/postgresql_adapter.rb +20 -0
  9. data/lib/searchgasm/active_record/connection_adapters/sqlite_adapter.rb +21 -0
  10. data/lib/searchgasm/condition/base.rb +31 -10
  11. data/lib/searchgasm/condition/inclusive_descendant_of.rb +1 -1
  12. data/lib/searchgasm/condition/not_begin_with.rb +1 -1
  13. data/lib/searchgasm/condition/not_blank.rb +17 -0
  14. data/lib/searchgasm/condition/not_end_with.rb +1 -1
  15. data/lib/searchgasm/condition/not_equal.rb +1 -1
  16. data/lib/searchgasm/condition/not_have_keywords.rb +1 -1
  17. data/lib/searchgasm/condition/not_like.rb +1 -1
  18. data/lib/searchgasm/condition/not_nil.rb +17 -0
  19. data/lib/searchgasm/condition/sibling_of.rb +1 -1
  20. data/lib/searchgasm/conditions/base.rb +9 -7
  21. data/lib/searchgasm/conditions/protection.rb +1 -1
  22. data/lib/searchgasm/helpers/control_types/select.rb +1 -1
  23. data/lib/searchgasm/helpers/utilities.rb +1 -1
  24. data/lib/searchgasm/modifiers/lower.rb +15 -0
  25. data/lib/searchgasm/modifiers/ltrim.rb +15 -0
  26. data/lib/searchgasm/modifiers/rtrim.rb +15 -0
  27. data/lib/searchgasm/modifiers/trim.rb +15 -0
  28. data/lib/searchgasm/modifiers/upper.rb +15 -0
  29. data/lib/searchgasm/search/base.rb +44 -40
  30. data/lib/searchgasm/search/conditions.rb +0 -16
  31. data/lib/searchgasm/search/ordering.rb +0 -8
  32. data/lib/searchgasm/search/searching.rb +0 -6
  33. data/lib/searchgasm/version.rb +2 -2
  34. data/lib/searchgasm.rb +2 -2
  35. data/searchgasm.gemspec +22 -6
  36. data/test/fixtures/cats.yml +3 -0
  37. data/test/fixtures/dogs.yml +3 -0
  38. data/test/test_active_record_base.rb +4 -0
  39. data/test/test_condition_base.rb +4 -4
  40. data/test/test_condition_types.rb +27 -27
  41. data/test/test_conditions_base.rb +22 -1
  42. data/test/test_helper.rb +24 -5
  43. data/test/test_search_base.rb +12 -19
  44. data/test/test_search_conditions.rb +1 -11
  45. data/test/test_search_ordering.rb +3 -4
  46. data/{test/libs → test_libs}/acts_as_tree.rb +0 -0
  47. data/{test/libs → test_libs}/ordered_hash.rb +0 -0
  48. data/{test/libs → test_libs}/rexml_fix.rb +0 -0
  49. metadata +21 -5
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,14 @@
1
+ == 1.4.0 released 2008-10-08
2
+
3
+ * Fixed bug when duping or cloning to copy over instance vars instead of method values
4
+ * Fixed bug with older versions of ActiveRecord and creating an alias method chain on find in AssociationCollection
5
+ * Added modifiers: upper, lower, trim, ltrim, rtrim
6
+ * Added not_nil and not_blank conditions
7
+ * Modified conditions so that table name is a variable, this allows table name to be switched on the fly.
8
+ * Modified auto joins to return symbols instead of SQL. This allows AR to properly merge the joins and ultimately result in proper SQL when performing multiple complex scopes.
9
+ * Fixed conflicts between includes and joins, duplicate joins are not added. Includes are prioritized. This also makes ActiveRecord much more flexible. Now you can cherry pick included associations. And not have to worry about conflicting with joins.
10
+ * Modified ActiveRecord's default behavior to use inner joins with the :joins option. Inner joins impose limitations. When providing this as a "convenience", inner joins do not make sense. The don't allow OR conditions to be across associations, nor does it properly order when an ordering by an association attribute when that association is optional.
11
+
1
12
  == 1.3.5 released 2008-10-08
2
13
 
3
14
  * Since joins are now strings, AR doesn't know how to merge them properly. So searchgasm now checks which joins to skip over to avoid conflicts.
data/Manifest CHANGED
@@ -22,10 +22,12 @@ lib/searchgasm/condition/less_than_or_equal_to.rb
22
22
  lib/searchgasm/condition/like.rb
23
23
  lib/searchgasm/condition/nil.rb
24
24
  lib/searchgasm/condition/not_begin_with.rb
25
+ lib/searchgasm/condition/not_blank.rb
25
26
  lib/searchgasm/condition/not_end_with.rb
26
27
  lib/searchgasm/condition/not_equal.rb
27
28
  lib/searchgasm/condition/not_have_keywords.rb
28
29
  lib/searchgasm/condition/not_like.rb
30
+ lib/searchgasm/condition/not_nil.rb
29
31
  lib/searchgasm/condition/sibling_of.rb
30
32
  lib/searchgasm/condition/tree.rb
31
33
  lib/searchgasm/conditions/base.rb
@@ -60,6 +62,8 @@ lib/searchgasm/modifiers/hour.rb
60
62
  lib/searchgasm/modifiers/log.rb
61
63
  lib/searchgasm/modifiers/log10.rb
62
64
  lib/searchgasm/modifiers/log2.rb
65
+ lib/searchgasm/modifiers/lower.rb
66
+ lib/searchgasm/modifiers/ltrim.rb
63
67
  lib/searchgasm/modifiers/md5.rb
64
68
  lib/searchgasm/modifiers/microseconds.rb
65
69
  lib/searchgasm/modifiers/milliseconds.rb
@@ -68,11 +72,14 @@ lib/searchgasm/modifiers/month.rb
68
72
  lib/searchgasm/modifiers/octal.rb
69
73
  lib/searchgasm/modifiers/radians.rb
70
74
  lib/searchgasm/modifiers/round.rb
75
+ lib/searchgasm/modifiers/rtrim.rb
71
76
  lib/searchgasm/modifiers/second.rb
72
77
  lib/searchgasm/modifiers/sign.rb
73
78
  lib/searchgasm/modifiers/sin.rb
74
79
  lib/searchgasm/modifiers/square_root.rb
75
80
  lib/searchgasm/modifiers/tan.rb
81
+ lib/searchgasm/modifiers/trim.rb
82
+ lib/searchgasm/modifiers/upper.rb
76
83
  lib/searchgasm/modifiers/week.rb
77
84
  lib/searchgasm/modifiers/year.rb
78
85
  lib/searchgasm/search/base.rb
@@ -90,12 +97,11 @@ MIT-LICENSE
90
97
  Rakefile
91
98
  README.rdoc
92
99
  test/fixtures/accounts.yml
100
+ test/fixtures/cats.yml
101
+ test/fixtures/dogs.yml
93
102
  test/fixtures/orders.yml
94
103
  test/fixtures/user_groups.yml
95
104
  test/fixtures/users.yml
96
- test/libs/acts_as_tree.rb
97
- test/libs/ordered_hash.rb
98
- test/libs/rexml_fix.rb
99
105
  test/test_active_record_associations.rb
100
106
  test/test_active_record_base.rb
101
107
  test/test_condition_base.rb
@@ -109,4 +115,7 @@ test/test_search_conditions.rb
109
115
  test/test_search_ordering.rb
110
116
  test/test_search_pagination.rb
111
117
  test/test_search_protection.rb
118
+ test_libs/acts_as_tree.rb
119
+ test_libs/ordered_hash.rb
120
+ test_libs/rexml_fix.rb
112
121
  TODO.rdoc
data/README.rdoc CHANGED
@@ -305,6 +305,11 @@ Here are all of the available modifiers:
305
305
 
306
306
  :md5 Converts to a MD5
307
307
  :char_length :length The length of the string (integer)
308
+ :lower :downcase, :lcase Converts the string to all lower case characters
309
+ :ltrin :lstrip Strips off spaces from the beginning of the string
310
+ :trim :strip Strips off spaces from the beginning and end of the string
311
+ :rtrim :rstrip Strips off spaces from the end of the string
312
+ :upper :upcase, :ucase Converts the string to all upper case character
308
313
 
309
314
  :absolute :abs The absolute value (-1 => 1)
310
315
  :acos The arc cosine
@@ -344,6 +349,12 @@ Here's the cool part. Chaining modifiers:
344
349
 
345
350
  As long as the modifier chain makes sense the possibilities are endless.
346
351
 
352
+ === Modifiers are not indexed
353
+
354
+ Depending on your database you can create complex indexes. But chances are you probably didn't or don't plan to. So keep in mind that once you use a modifier it will not be using an index, meaning the query will be slower. One of the ways to get the best of both worlds is to cache virtual attributes in the database. Checkout my tutorial:
355
+
356
+ http://www.binarylogic.com/2008/10/5/tutorial-caching-virtual-attributes-in-the-database
357
+
347
358
  == Roll your own conditions & modifiers
348
359
 
349
360
  For more information on this please see Searchgasm::Conditions::Base
data/TODO.rdoc CHANGED
@@ -1,3 +1,6 @@
1
1
  = To Do
2
2
 
3
- 1. Perform "more efficient" checks: year_of_created_at = 2008 and month_of_created_at = 8. Should result in a "BETWEEN" statement utilizing the column indexes. Thanks Georg for letting me know about this.
3
+ 1. Perform "more efficient" checks: year_of_created_at = 2008 and month_of_created_at = 8. Should result in a "BETWEEN" statement utilizing the column indexes. Thanks Georg for letting me know about this.
4
+ 2. Solve conflicts between scope joins and joins in the search (for old versions of AR). Also solve conflicts between joins and includes.
5
+ 3. Add configuration to change the "english" words
6
+ 4. Re-add the distinct option
@@ -13,7 +13,7 @@ module Searchgasm
13
13
  end
14
14
  end
15
15
 
16
- module Shared
16
+ module HasManyAssociation
17
17
  def count_with_searchgasm(*args)
18
18
  options = args.extract_options!
19
19
  args << filter_options_with_searchgasm(options)
@@ -24,18 +24,29 @@ module Searchgasm
24
24
  end
25
25
  end
26
26
 
27
- module ActiveRecord
28
- module Associations
29
- class AssociationCollection
30
- include Searchgasm::ActiveRecord::Associations::AssociationCollection
31
-
32
- alias_method_chain :find, :searchgasm
33
- end
34
-
35
- class HasManyAssociation
36
- include Searchgasm::ActiveRecord::Associations::Shared
37
-
38
- alias_method_chain :count, :searchgasm
39
- end
27
+ ActiveRecord::Associations::AssociationCollection.class_eval do
28
+ if respond_to?(:find)
29
+ include Searchgasm::ActiveRecord::Associations::AssociationCollection
30
+ alias_method_chain :find, :searchgasm
40
31
  end
32
+ end
33
+
34
+ ActiveRecord::Associations::HasManyAssociation.class_eval do
35
+ include Searchgasm::ActiveRecord::Associations::HasManyAssociation
36
+ alias_method_chain :count, :searchgasm
37
+
38
+ # Older versions of AR have find in here, not in AssociationCollection
39
+ include Searchgasm::ActiveRecord::Associations::AssociationCollection
40
+ alias_method_chain :find, :searchgasm
41
+ end
42
+
43
+ ActiveRecord::Associations::ClassMethods::InnerJoinDependency::InnerJoinAssociation.class_eval do
44
+ private
45
+ # Inner joins impose limitations on queries. They can be quicker but you can't do OR conditions when conditions
46
+ # overlap from the base model to any of its associations. Also, inner joins won't allow you to order by an association
47
+ # attribute. What if the association is optional? All of those records are ommitted. It just doesn't make sense to default
48
+ # to inner joins when providing this as a "convenience" when searching. So let's change it.
49
+ def join_type
50
+ "LEFT OUTER JOIN"
51
+ end
41
52
  end
@@ -165,6 +165,55 @@ module ActiveRecord #:nodoc: all
165
165
  def valid_calculations_options
166
166
  Calculations::CALCULATIONS_OPTIONS
167
167
  end
168
+
169
+ private
170
+ # This is copied over from 2 different versions of ActiveRecord. I have to do this in order to preserve the "auto joins"
171
+ # as symbols. Keeping them as symbols allows ActiveRecord to merge them properly. The problem is when they conflict with includes.
172
+ # Includes add joins also, and they add them before joins do. So if they already added them skip them. Now you can do queries like:
173
+ #
174
+ # User.all(:joins => {:orders => :line_items}, :include => :orders)
175
+ #
176
+ # Where as before, the only way to get the above query to work would be to include line_items also, which is not neccessarily what you want.
177
+ def add_joins!(sql, options_or_joins, scope = :auto) # :nodoc:
178
+ code_type = array_of_strings?([""]) && :array_of_strings rescue nil
179
+ code_type ||= merge_joins("", "") && :merge_joins rescue nil
180
+
181
+ case code_type
182
+ when :array_of_strings, :merge_joins
183
+ joins = options_or_joins
184
+ scope = scope(:find) if :auto == scope
185
+ merged_joins = scope && scope[:joins] && joins ? merge_joins(scope[:joins], joins) : (joins || scope && scope[:joins])
186
+ case merged_joins
187
+ when Symbol, Hash, Array
188
+ if code_type == :array_of_strings && array_of_strings?(merged_joins)
189
+ merged_joins.each { |merged_join| sql << " #{merged_join} " unless sql.include?(merged_join) }
190
+ else
191
+ join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, merged_joins, nil)
192
+ join_dependency.join_associations.each do |assoc|
193
+ join_sql = assoc.association_join
194
+ sql << " #{join_sql} " unless sql.include?(join_sql)
195
+ end
196
+ end
197
+ when String
198
+ sql << " #{merged_joins} " if merged_joins && !sql.include?(merged_joins)
199
+ end
200
+ else
201
+ options = options_or_joins
202
+ scope = scope(:find) if :auto == scope
203
+ [(scope && scope[:joins]), options[:joins]].each do |join|
204
+ case join
205
+ when Symbol, Hash, Array
206
+ join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, join, nil)
207
+ join_dependency.join_associations.each do |assoc|
208
+ join_sql = assoc.association_join
209
+ sql << " #{join_sql} " unless sql.include?(join_sql)
210
+ end
211
+ else
212
+ sql << " #{join} " if join && !sql.include?(join)
213
+ end
214
+ end
215
+ end
216
+ end
168
217
  end
169
218
  end
170
219
  end
@@ -52,10 +52,30 @@ module Searchgasm
52
52
  "CHAR_LENGTH(#{column_name})"
53
53
  end
54
54
 
55
+ def lower_sql(column_name)
56
+ "LOWER(#{column_name})"
57
+ end
58
+
59
+ def ltrim_sql(column_name)
60
+ "LTRIM(#{column_name})"
61
+ end
62
+
55
63
  def md5_sql(column_name)
56
64
  "MD5(#{column_name})"
57
65
  end
58
66
 
67
+ def rtrim_sql(column_name)
68
+ "RTRIM(#{column_name})"
69
+ end
70
+
71
+ def trim_sql(column_name)
72
+ "TRIM(#{column_name})"
73
+ end
74
+
75
+ def upper_sql(column_name)
76
+ "UPPER(#{column_name})"
77
+ end
78
+
59
79
  # Number functions
60
80
  def absolute_sql(column_name)
61
81
  "ABS(#{column_name})"
@@ -52,10 +52,30 @@ module Searchgasm
52
52
  "length(#{column_name})"
53
53
  end
54
54
 
55
+ def lower_sql(column_name)
56
+ "lower(#{column_name})"
57
+ end
58
+
59
+ def ltrim_sql(column_name)
60
+ "ltrim(#{column_name})"
61
+ end
62
+
55
63
  def md5_sql(column_name)
56
64
  "md5(#{column_name})"
57
65
  end
58
66
 
67
+ def rtrim_sql(column_name)
68
+ "rtrim(#{column_name})"
69
+ end
70
+
71
+ def trim_sql(column_name)
72
+ "trim(#{column_name})"
73
+ end
74
+
75
+ def upper_sql(column_name)
76
+ "upper(#{column_name})"
77
+ end
78
+
59
79
  # Number functions
60
80
  def absolute_sql(column_name)
61
81
  "abs(#{column_name})"
@@ -46,6 +46,27 @@ module Searchgasm
46
46
  def year_sql(column_name)
47
47
  "strftime('%Y', #{column_name})"
48
48
  end
49
+
50
+ # String functions
51
+ def lower_sql(column_name)
52
+ "lower(#{column_name})"
53
+ end
54
+
55
+ def ltrim_sql(column_name)
56
+ "ltrim(#{column_name})"
57
+ end
58
+
59
+ def rtrim_sql(column_name)
60
+ "rtrim(#{column_name})"
61
+ end
62
+
63
+ def trim_sql(column_name)
64
+ "trim(#{column_name})"
65
+ end
66
+
67
+ def upper_sql(column_name)
68
+ "upper(#{column_name})"
69
+ end
49
70
  end
50
71
  end
51
72
  end
@@ -7,7 +7,7 @@ module Searchgasm
7
7
  class Base
8
8
  include Shared::Utilities
9
9
 
10
- attr_accessor :column, :column_for_type_cast, :column_sql, :klass
10
+ attr_accessor :column, :column_for_type_cast, :column_sql, :column_sql_format, :klass, :table_name
11
11
  class_inheritable_accessor :handle_array_value, :ignore_meaningless_value, :value_type
12
12
  self.ignore_meaningless_value = true
13
13
 
@@ -16,7 +16,7 @@ module Searchgasm
16
16
  def condition_type_name
17
17
  name.split("::").last.underscore
18
18
  end
19
-
19
+
20
20
  def handle_array_value?
21
21
  handle_array_value == true
22
22
  end
@@ -39,16 +39,29 @@ module Searchgasm
39
39
  end
40
40
  end
41
41
 
42
- def initialize(klass, column_obj = nil, column_type = nil, column_sql = nil)
42
+ def initialize(klass, options = {})
43
43
  self.klass = klass
44
-
45
- if column_obj
46
- self.column = column_obj.class < ::ActiveRecord::ConnectionAdapters::Column ? column_obj : klass.columns_hash[column_obj.to_s]
47
- type = (!self.class.value_type.blank? && self.class.value_type.to_s) || (!column_type.blank? && column_type.to_s) || column.sql_type
48
- self.column_for_type_cast = column.class.new(column.name, column.default.to_s, type, column.null)
49
- self.column_sql = column_sql || "#{klass.connection.quote_table_name(klass.table_name)}.#{klass.connection.quote_column_name(column.name)}"
44
+ self.table_name = options[:table_name] || klass.table_name
45
+
46
+ if options[:column]
47
+ self.column = options[:column].class < ::ActiveRecord::ConnectionAdapters::Column ? options[:column] : klass.columns_hash[options[:column].to_s]
48
+
49
+ if options[:column_for_type_cast]
50
+ self.column_for_type_cast = options[:column_for_type_cast]
51
+ else
52
+ type = (!self.class.value_type.blank? && self.class.value_type.to_s) || (!options[:column_type].blank? && options[:column_type].to_s) || column.sql_type
53
+ self.column_for_type_cast = column.class.new(column.name, column.default.to_s, type, column.null)
54
+ end
55
+
56
+ self.column_sql_format = options[:column_sql_format] || "{table}.{column}"
50
57
  end
51
58
  end
59
+
60
+ # Substitutes string vars with table and column name. Allows us to switch the column and table on the fly and have the condition update appropriately.
61
+ # The table name could be variable depending on the condition. Take STI and more than one child model is used in the condition, the first gets the parent table name, the rest get aliases.
62
+ def column_sql
63
+ column_sql_format.gsub("{table}", quoted_table_name).gsub("{column}", quoted_column_name)
64
+ end
52
65
 
53
66
  # Allows nils to be meaninful values
54
67
  def explicitly_set_value=(value)
@@ -60,6 +73,10 @@ module Searchgasm
60
73
  @explicitly_set_value == true
61
74
  end
62
75
 
76
+ def options
77
+ {:table_name => table_name, :column => column, :column_for_type_cast => column_for_type_cast, :column_sql_format => column_sql_format}
78
+ end
79
+
63
80
  # You should refrain from overwriting this method, it performs various tasks before callign your to_conditions method, allowing you to keep to_conditions simple.
64
81
  def sanitize(alt_value = nil) # :nodoc:
65
82
  return if value_is_meaningless?
@@ -107,12 +124,16 @@ module Searchgasm
107
124
  klass.connection.quote_column_name(column_name)
108
125
  end
109
126
 
127
+ def quoted_column_name
128
+ quote_column_name(column.name)
129
+ end
130
+
110
131
  def quote_table_name(table_name)
111
132
  klass.connection.quote_table_name(table_name)
112
133
  end
113
134
 
114
135
  def quoted_table_name
115
- quote_table_name(klass.table_name)
136
+ quote_table_name(table_name)
116
137
  end
117
138
 
118
139
  def type_cast_value(v)
@@ -2,7 +2,7 @@ module Searchgasm
2
2
  module Condition
3
3
  class InclusiveDescendantOf < Tree
4
4
  def to_conditions(value)
5
- condition = DescendantOf.new(klass, column)
5
+ condition = DescendantOf.new(klass, options)
6
6
  condition.value = value
7
7
  merge_conditions(["#{quoted_table_name}.#{quote_column_name(klass.primary_key)} = ?", (value.is_a?(klass) ? value.send(klass.primary_key) : value)], condition.sanitize, :any => true)
8
8
  end
@@ -8,7 +8,7 @@ module Searchgasm
8
8
  end
9
9
 
10
10
  def to_conditions(value)
11
- begin_with = BeginWith.new
11
+ begin_with = BeginWith.new(klass, options)
12
12
  begin_with.value = value
13
13
  conditions = being_with.to_conditions
14
14
  return conditions if conditions.blank?
@@ -0,0 +1,17 @@
1
+ module Searchgasm
2
+ module Condition
3
+ class NotBlank < Base
4
+ class << self
5
+ def condition_names_for_column
6
+ super + ["is_not_blank"]
7
+ end
8
+ end
9
+
10
+ def to_conditions(value)
11
+ blank = Blank.new(klass, options)
12
+ blank.value = !value
13
+ blank.to_conditions
14
+ end
15
+ end
16
+ end
17
+ end
@@ -8,7 +8,7 @@ module Searchgasm
8
8
  end
9
9
 
10
10
  def to_conditions(value)
11
- ends_with = EndsWith.new
11
+ ends_with = EndsWith.new(klass, options)
12
12
  ends_with.value = value
13
13
  conditions = ends_with.to_conditions
14
14
  return conditions if conditions.blank?
@@ -12,7 +12,7 @@ module Searchgasm
12
12
 
13
13
  def to_conditions(value)
14
14
  # Delegate to equals and then change
15
- condition = Equals.new(klass, column)
15
+ condition = Equals.new(klass, options)
16
16
  condition.value = value
17
17
 
18
18
  conditions_array = condition.sanitize
@@ -8,7 +8,7 @@ module Searchgasm
8
8
  end
9
9
 
10
10
  def to_conditions(value)
11
- keywords = Keywords.new
11
+ keywords = Keywords.new(klass, options)
12
12
  keywords.value = value
13
13
  conditions = keywords.to_conditions
14
14
  return conditions if conditions.blank?
@@ -8,7 +8,7 @@ module Searchgasm
8
8
  end
9
9
 
10
10
  def to_conditions(value)
11
- like = Like.new
11
+ like = Like.new(klass, options)
12
12
  like.value = value
13
13
  conditions = like.to_conditions
14
14
  return conditions if conditions.blank?
@@ -0,0 +1,17 @@
1
+ module Searchgasm
2
+ module Condition
3
+ class NotNil < Base
4
+ class << self
5
+ def condition_names_for_column
6
+ super + ["is_not_nil", "is_not_null", "not_null"]
7
+ end
8
+ end
9
+
10
+ def to_conditions(value)
11
+ is_nil = Nil.new(klass, options)
12
+ is_nil.value = !value
13
+ is_nil.to_conditions
14
+ end
15
+ end
16
+ end
17
+ end
@@ -5,7 +5,7 @@ module Searchgasm
5
5
  parent_association = klass.reflect_on_association(:parent)
6
6
  foreign_key_name = (parent_association && parent_association.options[:foreign_key]) || "parent_id"
7
7
  parent_id = (value.is_a?(klass) ? value : klass.find(value)).send(foreign_key_name)
8
- condition = ChildOf.new(klass, column)
8
+ condition = ChildOf.new(klass, options)
9
9
  condition.value = parent_id
10
10
  merge_conditions(["#{quoted_table_name}.#{quote_column_name(klass.primary_key)} != ?", (value.is_a?(klass) ? value.send(klass.primary_key) : value)], condition.sanitize)
11
11
  end
@@ -179,7 +179,7 @@ module Searchgasm
179
179
  associations.each do |name, association|
180
180
  next if association.conditions.blank?
181
181
  association_joins = association.auto_joins
182
- j << (association_joins.blank? ? association.relationship_name.to_sym : {association.relationship_name.to_sym => association_joins})
182
+ j << (association_joins.blank? ? name : {name => association_joins})
183
183
  end
184
184
  j.blank? ? nil : (j.size == 1 ? j.first : j)
185
185
  end
@@ -233,7 +233,7 @@ module Searchgasm
233
233
  if object.class < Searchgasm::Conditions::Base
234
234
  relationship_conditions = object.conditions
235
235
  next if relationship_conditions.blank?
236
- conditions_hash[object.relationship_name.to_sym] = relationship_conditions
236
+ conditions_hash[name] = relationship_conditions
237
237
  else
238
238
  next if object.value_is_meaningless?
239
239
  conditions_hash[name] = object.value
@@ -367,14 +367,14 @@ module Searchgasm
367
367
  column_type = modifier_klasses.first.return_type
368
368
 
369
369
  # Build the column sql
370
- column_sql = "#{klass.connection.quote_table_name(klass.table_name)}.#{klass.connection.quote_column_name(column_detail[:column].name)}"
370
+ column_sql = "{table}.{column}"
371
371
  modifier_klasses.each do |modifier_klass|
372
372
  next unless klass.connection.respond_to?(modifier_klass.adapter_method_name)
373
373
  column_sql = klass.connection.send(modifier_klass.adapter_method_name, column_sql)
374
374
  end
375
375
  end
376
376
 
377
- add_condition!(condition_klass, method_name, column_detail[:column], column_type, column_sql)
377
+ add_condition!(condition_klass, method_name, :column => column_detail[:column], :column_type => column_type, :column_sql_format => column_sql)
378
378
 
379
379
  ([column_detail[:column].name] + column_detail[:aliases]).each do |column_name|
380
380
  condition_klass.condition_names_for_column.each do |condition_name|
@@ -393,13 +393,15 @@ module Searchgasm
393
393
  false
394
394
  end
395
395
 
396
- def add_condition!(condition, name, column = nil, column_type = nil, column_sql = nil)
396
+ def add_condition!(condition, name, options = {})
397
397
  self.class.condition_names << name
398
+ options[:column] = options[:column].name if options[:column].class < ::ActiveRecord::ConnectionAdapters::Column
398
399
 
399
400
  self.class.class_eval <<-"end_eval", __FILE__, __LINE__
400
401
  def #{name}_object
401
402
  if objects[:#{name}].nil?
402
- 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('"', '\"')}\""})
403
+ options = {}
404
+ objects[:#{name}] = #{condition.name}.new(klass, #{options.inspect})
403
405
  end
404
406
  objects[:#{name}]
405
407
  end
@@ -465,7 +467,7 @@ module Searchgasm
465
467
  end
466
468
 
467
469
  def reset_objects!
468
- objects.each { |name, object| object.class < ::Searchgasm::Conditions::Base ? eval("@#{object.relationship_name} = nil") : eval("@#{name} = nil") }
470
+ objects.each { |name, object| eval("@#{name} = nil") }
469
471
  objects.clear
470
472
  end
471
473
 
@@ -23,7 +23,7 @@ module Searchgasm
23
23
  end
24
24
 
25
25
  def protect=(value)
26
- associations.each { |association| association.protect = value }
26
+ associations.each { |name, obj| obj.protect = value }
27
27
  @protect = value
28
28
  end
29
29
 
@@ -68,7 +68,7 @@ module Searchgasm
68
68
  else
69
69
  options[:html][:onchange] += remote_function(:url => url, :method => :get).gsub(/\\'\+this.value\+\\'/, "'+this.value+'")
70
70
  end
71
- options[:html][:id] ||= ""
71
+ options[:html][:id] ||= "#{option}_select"
72
72
  options
73
73
  end
74
74
  end
@@ -105,7 +105,7 @@ module Searchgasm
105
105
  # === Options
106
106
  # * <tt>:params_scope</tt> -- default: :search, this is the scope in which your search params will be preserved (params[:search]). If you don't want a scope and want your options to be at base leve in params such as params[:page], params[:per_page], etc, then set this to nil.
107
107
  # * <tt>:search_obj</tt> -- default: @#{params_scope}, this is your search object, everything revolves around this. It will try to infer the name from your params_scope. If your params_scope is :search it will try to get @search, etc. If it can not be inferred by this, you need to pass the object itself.
108
- def searchgasm_state(options)
108
+ def searchgasm_state(options = {})
109
109
  return "" if @added_searchgasm_state
110
110
  add_searchgasm_defaults!(options)
111
111
  html = ""
@@ -0,0 +1,15 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Lower < Base
4
+ class << self
5
+ def modifier_names
6
+ super + ["downcase", "lcase"]
7
+ end
8
+
9
+ def return_type
10
+ :string
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Ltrim < Base
4
+ class << self
5
+ def modifier_names
6
+ super + ["lstrip"]
7
+ end
8
+
9
+ def return_type
10
+ :string
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Rtrim < Base
4
+ class << self
5
+ def modifier_names
6
+ super + ["rstrip"]
7
+ end
8
+
9
+ def return_type
10
+ :string
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Searchgasm
2
+ module Modifiers
3
+ class Trim < Base
4
+ class << self
5
+ def modifier_names
6
+ super + ["strip"]
7
+ end
8
+
9
+ def return_type
10
+ :string
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end