searchlogic 1.6.6 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/CHANGELOG.rdoc +17 -0
- data/{MIT-LICENSE → LICENSE} +2 -2
- data/README.rdoc +128 -379
- data/Rakefile +56 -20
- data/VERSION.yml +4 -0
- data/init.rb +1 -1
- data/lib/searchlogic.rb +18 -98
- data/lib/searchlogic/core_ext/object.rb +33 -13
- data/lib/searchlogic/core_ext/proc.rb +11 -0
- data/lib/searchlogic/named_scopes/alias_scope.rb +63 -0
- data/lib/searchlogic/named_scopes/associations.rb +126 -0
- data/lib/searchlogic/named_scopes/conditions.rb +215 -0
- data/lib/searchlogic/named_scopes/ordering.rb +53 -0
- data/lib/searchlogic/rails_helpers.rb +69 -0
- data/lib/searchlogic/search.rb +146 -0
- data/rails/init.rb +1 -0
- data/searchlogic.gemspec +69 -0
- data/spec/core_ext/object_spec.rb +7 -0
- data/spec/core_ext/proc_spec.rb +9 -0
- data/spec/named_scopes/alias_scope_spec.rb +15 -0
- data/spec/named_scopes/associations_spec.rb +120 -0
- data/spec/named_scopes/conditions_spec.rb +253 -0
- data/spec/named_scopes/ordering_spec.rb +23 -0
- data/spec/search_spec.rb +283 -0
- data/spec/spec_helper.rb +78 -0
- metadata +40 -231
- data/Manifest.txt +0 -158
- data/TODO.rdoc +0 -4
- data/lib/searchlogic/active_record/associations.rb +0 -52
- data/lib/searchlogic/active_record/base.rb +0 -224
- data/lib/searchlogic/active_record/connection_adapters/mysql_adapter.rb +0 -176
- data/lib/searchlogic/active_record/connection_adapters/postgresql_adapter.rb +0 -172
- data/lib/searchlogic/active_record/connection_adapters/sqlite_adapter.rb +0 -80
- data/lib/searchlogic/condition/base.rb +0 -165
- data/lib/searchlogic/condition/begins_with.rb +0 -17
- data/lib/searchlogic/condition/blank.rb +0 -24
- data/lib/searchlogic/condition/child_of.rb +0 -11
- data/lib/searchlogic/condition/descendant_of.rb +0 -11
- data/lib/searchlogic/condition/ends_with.rb +0 -17
- data/lib/searchlogic/condition/equals.rb +0 -33
- data/lib/searchlogic/condition/greater_than.rb +0 -15
- data/lib/searchlogic/condition/greater_than_or_equal_to.rb +0 -15
- data/lib/searchlogic/condition/inclusive_descendant_of.rb +0 -10
- data/lib/searchlogic/condition/keywords.rb +0 -52
- data/lib/searchlogic/condition/less_than.rb +0 -15
- data/lib/searchlogic/condition/less_than_or_equal_to.rb +0 -15
- data/lib/searchlogic/condition/like.rb +0 -15
- data/lib/searchlogic/condition/nested_set.rb +0 -17
- data/lib/searchlogic/condition/nil.rb +0 -21
- data/lib/searchlogic/condition/not_begin_with.rb +0 -20
- data/lib/searchlogic/condition/not_blank.rb +0 -19
- data/lib/searchlogic/condition/not_end_with.rb +0 -20
- data/lib/searchlogic/condition/not_equal.rb +0 -27
- data/lib/searchlogic/condition/not_have_keywords.rb +0 -20
- data/lib/searchlogic/condition/not_like.rb +0 -20
- data/lib/searchlogic/condition/not_nil.rb +0 -19
- data/lib/searchlogic/condition/sibling_of.rb +0 -14
- data/lib/searchlogic/conditions/any_or_all.rb +0 -42
- data/lib/searchlogic/conditions/base.rb +0 -244
- data/lib/searchlogic/conditions/groups.rb +0 -74
- data/lib/searchlogic/conditions/magic_methods.rb +0 -286
- data/lib/searchlogic/conditions/multiparameter_attributes.rb +0 -105
- data/lib/searchlogic/conditions/protection.rb +0 -36
- data/lib/searchlogic/config.rb +0 -31
- data/lib/searchlogic/config/helpers.rb +0 -338
- data/lib/searchlogic/config/search.rb +0 -53
- data/lib/searchlogic/core_ext/hash.rb +0 -75
- data/lib/searchlogic/helpers/control_types/link.rb +0 -310
- data/lib/searchlogic/helpers/control_types/links.rb +0 -242
- data/lib/searchlogic/helpers/control_types/remote_link.rb +0 -87
- data/lib/searchlogic/helpers/control_types/remote_links.rb +0 -72
- data/lib/searchlogic/helpers/control_types/remote_select.rb +0 -36
- data/lib/searchlogic/helpers/control_types/select.rb +0 -82
- data/lib/searchlogic/helpers/form.rb +0 -208
- data/lib/searchlogic/helpers/utilities.rb +0 -197
- data/lib/searchlogic/modifiers/absolute.rb +0 -15
- data/lib/searchlogic/modifiers/acos.rb +0 -11
- data/lib/searchlogic/modifiers/asin.rb +0 -11
- data/lib/searchlogic/modifiers/atan.rb +0 -11
- data/lib/searchlogic/modifiers/avg.rb +0 -15
- data/lib/searchlogic/modifiers/base.rb +0 -27
- data/lib/searchlogic/modifiers/ceil.rb +0 -15
- data/lib/searchlogic/modifiers/char_length.rb +0 -15
- data/lib/searchlogic/modifiers/cos.rb +0 -15
- data/lib/searchlogic/modifiers/cot.rb +0 -15
- data/lib/searchlogic/modifiers/count.rb +0 -11
- data/lib/searchlogic/modifiers/day_of_month.rb +0 -15
- data/lib/searchlogic/modifiers/day_of_week.rb +0 -15
- data/lib/searchlogic/modifiers/day_of_year.rb +0 -15
- data/lib/searchlogic/modifiers/degrees.rb +0 -11
- data/lib/searchlogic/modifiers/exp.rb +0 -15
- data/lib/searchlogic/modifiers/floor.rb +0 -15
- data/lib/searchlogic/modifiers/hex.rb +0 -11
- data/lib/searchlogic/modifiers/hour.rb +0 -11
- data/lib/searchlogic/modifiers/log.rb +0 -15
- data/lib/searchlogic/modifiers/log10.rb +0 -11
- data/lib/searchlogic/modifiers/log2.rb +0 -11
- data/lib/searchlogic/modifiers/lower.rb +0 -15
- data/lib/searchlogic/modifiers/ltrim.rb +0 -15
- data/lib/searchlogic/modifiers/md5.rb +0 -11
- data/lib/searchlogic/modifiers/microseconds.rb +0 -11
- data/lib/searchlogic/modifiers/milliseconds.rb +0 -11
- data/lib/searchlogic/modifiers/minute.rb +0 -15
- data/lib/searchlogic/modifiers/month.rb +0 -15
- data/lib/searchlogic/modifiers/octal.rb +0 -15
- data/lib/searchlogic/modifiers/radians.rb +0 -11
- data/lib/searchlogic/modifiers/round.rb +0 -11
- data/lib/searchlogic/modifiers/rtrim.rb +0 -15
- data/lib/searchlogic/modifiers/second.rb +0 -15
- data/lib/searchlogic/modifiers/sign.rb +0 -11
- data/lib/searchlogic/modifiers/sin.rb +0 -11
- data/lib/searchlogic/modifiers/square_root.rb +0 -15
- data/lib/searchlogic/modifiers/sum.rb +0 -11
- data/lib/searchlogic/modifiers/tan.rb +0 -15
- data/lib/searchlogic/modifiers/trim.rb +0 -15
- data/lib/searchlogic/modifiers/upper.rb +0 -15
- data/lib/searchlogic/modifiers/week.rb +0 -11
- data/lib/searchlogic/modifiers/year.rb +0 -11
- data/lib/searchlogic/search/base.rb +0 -148
- data/lib/searchlogic/search/conditions.rb +0 -53
- data/lib/searchlogic/search/ordering.rb +0 -244
- data/lib/searchlogic/search/pagination.rb +0 -121
- data/lib/searchlogic/search/protection.rb +0 -89
- data/lib/searchlogic/search/searching.rb +0 -32
- data/lib/searchlogic/shared/utilities.rb +0 -57
- data/lib/searchlogic/shared/virtual_classes.rb +0 -39
- data/lib/searchlogic/version.rb +0 -79
- data/test/active_record_tests/associations_test.rb +0 -94
- data/test/active_record_tests/base_test.rb +0 -115
- data/test/condition_tests/base_test.rb +0 -62
- data/test/condition_tests/begins_with_test.rb +0 -11
- data/test/condition_tests/blank_test.rb +0 -31
- data/test/condition_tests/child_of_test.rb +0 -17
- data/test/condition_tests/descendant_of_test.rb +0 -12
- data/test/condition_tests/ends_with_test.rb +0 -11
- data/test/condition_tests/equals_test.rb +0 -28
- data/test/condition_tests/greater_than_or_equal_to_test.rb +0 -11
- data/test/condition_tests/greater_than_test.rb +0 -11
- data/test/condition_tests/inclusive_descendant_of_test.rb +0 -12
- data/test/condition_tests/keywords_test.rb +0 -23
- data/test/condition_tests/less_than_or_equal_to_test.rb +0 -11
- data/test/condition_tests/less_than_test.rb +0 -11
- data/test/condition_tests/like_test.rb +0 -11
- data/test/condition_tests/nil_test.rb +0 -31
- data/test/condition_tests/not_begin_with_test.rb +0 -8
- data/test/condition_tests/not_blank_test.rb +0 -8
- data/test/condition_tests/not_end_with_test.rb +0 -8
- data/test/condition_tests/not_equal_test.rb +0 -19
- data/test/condition_tests/not_have_keywords_test.rb +0 -8
- data/test/condition_tests/not_like_test.rb +0 -8
- data/test/condition_tests/not_nil_test.rb +0 -13
- data/test/condition_tests/sibling_of_test.rb +0 -15
- data/test/conditions_tests/any_or_all_test.rb +0 -23
- data/test/conditions_tests/base_test.rb +0 -185
- data/test/conditions_tests/groups_test.rb +0 -68
- data/test/conditions_tests/magic_methods_test.rb +0 -36
- data/test/conditions_tests/multiparameter_attributes_test.rb +0 -15
- data/test/conditions_tests/protection_test.rb +0 -18
- data/test/config_test.rb +0 -23
- data/test/fixtures/accounts.yml +0 -12
- data/test/fixtures/animals.yml +0 -7
- data/test/fixtures/orders.yml +0 -12
- data/test/fixtures/user_groups.yml +0 -5
- data/test/fixtures/users.yml +0 -45
- data/test/libs/awesome_nested_set.rb +0 -545
- data/test/libs/awesome_nested_set/.autotest +0 -13
- data/test/libs/awesome_nested_set/compatability.rb +0 -29
- data/test/libs/awesome_nested_set/helper.rb +0 -40
- data/test/libs/awesome_nested_set/named_scope.rb +0 -140
- data/test/libs/rexml_fix.rb +0 -14
- data/test/modifier_tests/day_of_month_test.rb +0 -16
- data/test/search_tests/base_test.rb +0 -241
- data/test/search_tests/conditions_test.rb +0 -21
- data/test/search_tests/ordering_test.rb +0 -167
- data/test/search_tests/pagination_test.rb +0 -74
- data/test/search_tests/protection_test.rb +0 -26
- data/test/test_helper.rb +0 -122
@@ -1,244 +0,0 @@
|
|
1
|
-
module Searchlogic
|
2
|
-
module Conditions # :nodoc:
|
3
|
-
# = Conditions
|
4
|
-
#
|
5
|
-
# Represents a collection of conditions and performs various tasks on that collection. For information on each condition see Searchlogic::Condition.
|
6
|
-
# Each condition has its own file and class and the source for each condition is pretty self explanatory.
|
7
|
-
class Base
|
8
|
-
include Shared::Utilities
|
9
|
-
include Shared::VirtualClasses
|
10
|
-
|
11
|
-
attr_accessor :object_name
|
12
|
-
|
13
|
-
class << self
|
14
|
-
# 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.
|
15
|
-
#
|
16
|
-
# === Example
|
17
|
-
#
|
18
|
-
# # config/initializers/searchlogic.rb
|
19
|
-
# # Actual function for MySQL databases only
|
20
|
-
# class SoundsLike < Searchlogic::Condition::Base
|
21
|
-
# # The name of the conditions. By default its the name of the class, if you want alternate or alias conditions just add them on.
|
22
|
-
# # If you don't want to add aliases you don't even need to define this method
|
23
|
-
# def self.condition_names_for_column
|
24
|
-
# super + ["similar_to", "sounds"]
|
25
|
-
# end
|
26
|
-
#
|
27
|
-
# # You can return an array or a string. NOT a hash, because all of these conditions
|
28
|
-
# # need to eventually get merged together. The array or string can be anything you would put in
|
29
|
-
# # the :conditions option for ActiveRecord::Base.find(). Also notice the column_sql variable. This is essentail
|
30
|
-
# # for applying modifiers and should be used in your conditions wherever you want the column.
|
31
|
-
# def to_conditions(value)
|
32
|
-
# ["#{column_sql} SOUNDS LIKE ?", value]
|
33
|
-
# end
|
34
|
-
# end
|
35
|
-
#
|
36
|
-
# Searchlogic::Conditions::Base.register_condition(SoundsLike)
|
37
|
-
def register_condition(condition_class)
|
38
|
-
raise(ArgumentError, "You can only register conditions that extend Searchlogic::Condition::Base") unless condition_class.ancestors.include?(Searchlogic::Condition::Base)
|
39
|
-
conditions << condition_class unless conditions.include?(condition_class)
|
40
|
-
end
|
41
|
-
|
42
|
-
# A list of available condition type classes
|
43
|
-
def conditions
|
44
|
-
@@conditions ||= []
|
45
|
-
end
|
46
|
-
|
47
|
-
# Registers a modifier as an available modifier for each column.
|
48
|
-
#
|
49
|
-
# === Example
|
50
|
-
#
|
51
|
-
# # config/initializers/searchlogic.rb
|
52
|
-
# class Ceil < Searchlogic::Modifiers::Base
|
53
|
-
# # The name of the modifier. By default its the name of the class, if you want alternate or alias modifiers just add them on.
|
54
|
-
# # If you don't want to add aliases you don't even need to define this method
|
55
|
-
# def self.modifier_names
|
56
|
-
# super + ["round_up"]
|
57
|
-
# end
|
58
|
-
#
|
59
|
-
# # The name of the method in the connection adapters (see below). By default its the name of your class suffixed with "_sql".
|
60
|
-
# # So in this example it would be "ceil_sql". Unless you want to change that you don't need to define this method.
|
61
|
-
# def self.adapter_method_name
|
62
|
-
# super
|
63
|
-
# end
|
64
|
-
#
|
65
|
-
# # This is the type of value returned from the modifier. This is neccessary for typcasting values for the modifier when
|
66
|
-
# # applied to a column
|
67
|
-
# def self.return_type
|
68
|
-
# :integer
|
69
|
-
# end
|
70
|
-
# end
|
71
|
-
#
|
72
|
-
# Searchlogic::Seearch::Conditions.register_modifiers(Ceil)
|
73
|
-
#
|
74
|
-
# 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
|
75
|
-
# add in the function to ActiveRecord::ConnectionAdapters::AbstractAdapter, otherwise you need to add them to each
|
76
|
-
# individually: ActiveRecord::ConnectionAdapters::MysqlAdapter, ActiveRecord::ConnectionAdapters::PostgreSQLAdapter, ActiveRecord::ConnectionAdapters::SQLiteAdapter
|
77
|
-
#
|
78
|
-
# 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"
|
79
|
-
#
|
80
|
-
# module CeilAdapterMethod
|
81
|
-
# def ceil_sql(column_name)
|
82
|
-
# "CEIL(#{column_name})"
|
83
|
-
# end
|
84
|
-
# end
|
85
|
-
#
|
86
|
-
# ActiveRecord::ConnectionAdapters::MysqlAdapter.send(:include, CeilAdapterMethod)
|
87
|
-
# # ... include for the rest of the adapters
|
88
|
-
def register_modifier(modifier_class)
|
89
|
-
raise(ArgumentError, "You can only register conditions that extend Searchlogic::Modifiers::Base") unless modifier_class.ancestors.include?(Searchlogic::Modifiers::Base)
|
90
|
-
modifiers << modifier_class unless modifiers.include?(modifier_class)
|
91
|
-
end
|
92
|
-
|
93
|
-
# A list of available modifier classes
|
94
|
-
def modifiers
|
95
|
-
@@modifiers ||= []
|
96
|
-
end
|
97
|
-
|
98
|
-
def needed?(model_class, conditions) # :nodoc:
|
99
|
-
return false if conditions.blank?
|
100
|
-
|
101
|
-
if conditions.is_a?(Hash)
|
102
|
-
return true if conditions[:any]
|
103
|
-
stringified_conditions = conditions.stringify_keys
|
104
|
-
stringified_conditions.keys.each { |condition| return false if condition.include?(".") } # setting conditions on associations, which is just another way of writing SQL, and we ignore SQL
|
105
|
-
|
106
|
-
column_names = model_class.column_names
|
107
|
-
stringified_conditions.keys.each do |condition|
|
108
|
-
return true unless column_names.include?(condition)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
false
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# Initializes a conditions object, accepts a hash of conditions as the single parameter
|
117
|
-
def initialize(init_conditions = {})
|
118
|
-
self.conditions = init_conditions
|
119
|
-
end
|
120
|
-
|
121
|
-
# A list of joins to use when searching, includes relationships
|
122
|
-
def auto_joins
|
123
|
-
j = []
|
124
|
-
association_objects.each do |association|
|
125
|
-
next if association.conditions.blank?
|
126
|
-
association_joins = association.auto_joins
|
127
|
-
j << (association_joins.blank? ? association.object_name : {association.object_name => association_joins})
|
128
|
-
end
|
129
|
-
j.blank? ? nil : (j.size == 1 ? j.first : j)
|
130
|
-
end
|
131
|
-
|
132
|
-
# Provides a much more informative and easier to understand inspection of the object
|
133
|
-
def inspect
|
134
|
-
"#<#{klass}Conditions#{conditions.blank? ? "" : " #{conditions.inspect}"}>"
|
135
|
-
end
|
136
|
-
|
137
|
-
# Sanitizes the conditions down into conditions that ActiveRecord::Base.find can understand.
|
138
|
-
def sanitize
|
139
|
-
return @conditions if @conditions # return the conditions if the user set them with a string, aka sql conditions
|
140
|
-
joined_conditions = nil
|
141
|
-
objects.each do |object|
|
142
|
-
sanitized_conditions = group?(object) ? scope_condition(object.sanitize) : object.sanitize
|
143
|
-
joined_conditions = merge_conditions(joined_conditions, sanitized_conditions, :any => join_object_with_any?(object))
|
144
|
-
end
|
145
|
-
joined_conditions
|
146
|
-
end
|
147
|
-
|
148
|
-
# Allows you to set the conditions via a hash.
|
149
|
-
def conditions=(value)
|
150
|
-
case value
|
151
|
-
when Array
|
152
|
-
value.each { |v| self.conditions = v }
|
153
|
-
when Hash
|
154
|
-
remove_conditions_from_protected_assignement(value).each do |condition, condition_value|
|
155
|
-
next if [:conditions].include?(condition.to_sym) # protect sensitive methods
|
156
|
-
|
157
|
-
# delete all blanks from mass assignments, forms submit blanks, blanks are meaningless
|
158
|
-
# equals condition thinks everything is meaningful, and arrays can be pased
|
159
|
-
new_condition_value = nil
|
160
|
-
case condition_value
|
161
|
-
when Array
|
162
|
-
new_condition_value = condition_value.reject { |v| v == "" }
|
163
|
-
next if new_condition_value.empty?
|
164
|
-
new_condition_value = new_condition_value.first if new_condition_value.size == 1
|
165
|
-
else
|
166
|
-
next if condition_value == ""
|
167
|
-
new_condition_value = condition_value
|
168
|
-
end
|
169
|
-
|
170
|
-
send("#{condition}=", new_condition_value)
|
171
|
-
end
|
172
|
-
else
|
173
|
-
reset!
|
174
|
-
@conditions = value
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
# All of the active conditions (conditions that have been set)
|
179
|
-
def conditions
|
180
|
-
return @conditions if @conditions
|
181
|
-
|
182
|
-
conditions_hash = {}
|
183
|
-
|
184
|
-
association_objects.each do |association_object|
|
185
|
-
relationship_conditions = association_object.conditions
|
186
|
-
next if relationship_conditions.blank?
|
187
|
-
conditions_hash[association_object.object_name] = relationship_conditions
|
188
|
-
end
|
189
|
-
|
190
|
-
condition_objects.each do |condition_object|
|
191
|
-
next if condition_object.value_is_meaningless?
|
192
|
-
conditions_hash[condition_object.object_name] = condition_object.value
|
193
|
-
end
|
194
|
-
|
195
|
-
conditions_hash
|
196
|
-
end
|
197
|
-
|
198
|
-
# Resets all of the conditions, including conditions set on associations
|
199
|
-
def reset!
|
200
|
-
objects.each { |object| eval("@#{object.object_name} = nil") }
|
201
|
-
objects.clear
|
202
|
-
end
|
203
|
-
|
204
|
-
private
|
205
|
-
def association_objects
|
206
|
-
objects.select { |object| association?(object) }
|
207
|
-
end
|
208
|
-
|
209
|
-
def association?(object)
|
210
|
-
object.class < Base && object.class != self.class
|
211
|
-
end
|
212
|
-
|
213
|
-
def condition_objects
|
214
|
-
objects.select { |object| condition?(object) }
|
215
|
-
end
|
216
|
-
|
217
|
-
def condition?(object)
|
218
|
-
object.class < Condition::Base
|
219
|
-
end
|
220
|
-
|
221
|
-
def objects
|
222
|
-
@objects ||= []
|
223
|
-
end
|
224
|
-
|
225
|
-
def join_object_with_any?(object)
|
226
|
-
return any? if !any.nil?
|
227
|
-
if condition?(object) || group?(object)
|
228
|
-
object.explicit_any?
|
229
|
-
elsif association?(object)
|
230
|
-
object.send(:join_object_with_any?, object.send(:objects).first)
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
def remove_conditions_from_protected_assignement(conditions)
|
235
|
-
return conditions if klass.accessible_conditions.nil? && klass.protected_conditions.nil?
|
236
|
-
if klass.accessible_conditions
|
237
|
-
conditions.reject { |condition, value| !klass.accessible_conditions.include?(condition.to_s) }
|
238
|
-
elsif klass.protected_conditions
|
239
|
-
conditions.reject { |condition, value| klass.protected_conditions.include?(condition.to_s) }
|
240
|
-
end
|
241
|
-
end
|
242
|
-
end
|
243
|
-
end
|
244
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
module Searchlogic
|
2
|
-
module Conditions
|
3
|
-
# = Groups
|
4
|
-
#
|
5
|
-
# Allows you to group conditions, similar to how you would group conditions with parenthesis in an SQL statement. See the "Group conditions" section in the READM for examples.
|
6
|
-
module Groups
|
7
|
-
def self.included(klass)
|
8
|
-
klass.class_eval do
|
9
|
-
alias_method_chain :auto_joins, :groups
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def auto_joins_with_groups
|
14
|
-
auto_joins = auto_joins_without_groups
|
15
|
-
auto_joins = auto_joins.is_a?(Array) ? auto_joins : [auto_joins].compact
|
16
|
-
|
17
|
-
group_objects.each do |group|
|
18
|
-
next if group.conditions.blank?
|
19
|
-
group_joins = group.auto_joins
|
20
|
-
next if group_joins.blank?
|
21
|
-
group_joins = group_joins.is_a?(Array) ? group_joins : [group_joins]
|
22
|
-
auto_joins += group_joins
|
23
|
-
end
|
24
|
-
|
25
|
-
auto_joins.blank? ? nil : (auto_joins.size == 1 ? auto_joins.first : auto_joins)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Creates a new group object to set condition off of. See examples at top of class on how to use this.
|
29
|
-
def group(conditions = nil, &block)
|
30
|
-
obj = self.class.new
|
31
|
-
obj.conditions = conditions unless conditions.nil?
|
32
|
-
yield obj if block_given?
|
33
|
-
objects << obj
|
34
|
-
obj
|
35
|
-
end
|
36
|
-
alias_method :group=, :group
|
37
|
-
|
38
|
-
def and_group(*args, &block)
|
39
|
-
obj = group(*args, &block)
|
40
|
-
obj.explicit_any = false
|
41
|
-
obj
|
42
|
-
end
|
43
|
-
alias_method :and_group=, :and_group
|
44
|
-
|
45
|
-
def or_group(*args, &block)
|
46
|
-
obj = group(*args, &block)
|
47
|
-
obj.explicit_any = true
|
48
|
-
obj
|
49
|
-
end
|
50
|
-
alias_method :or_group=, :or_group
|
51
|
-
|
52
|
-
def explicit_any=(value) # :nodoc:
|
53
|
-
@explicit_any = value
|
54
|
-
end
|
55
|
-
|
56
|
-
def explicit_any # :nodoc
|
57
|
-
@explicit_any
|
58
|
-
end
|
59
|
-
|
60
|
-
def explicit_any? # :nodoc:
|
61
|
-
["true", "1", "yes"].include? explicit_any.to_s
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
def group_objects
|
66
|
-
objects.select { |object| group?(object) }
|
67
|
-
end
|
68
|
-
|
69
|
-
def group?(object)
|
70
|
-
object.class == self.class
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
@@ -1,286 +0,0 @@
|
|
1
|
-
module Searchlogic
|
2
|
-
module Conditions
|
3
|
-
# = Magic Methods
|
4
|
-
#
|
5
|
-
# Handles all method magic, creating methods on the fly, etc. This is needed for modifiers.
|
6
|
-
module MagicMethods
|
7
|
-
def self.included(klass)
|
8
|
-
klass.metaclass.class_eval do
|
9
|
-
include ClassMethods
|
10
|
-
attr_accessor :added_class_level_conditions, :added_column_equals_conditions, :added_associations
|
11
|
-
end
|
12
|
-
|
13
|
-
klass.class_eval do
|
14
|
-
include InstanceMethods
|
15
|
-
alias_method_chain :initialize, :magic_methods
|
16
|
-
alias_method_chain :method_missing, :magic_methods
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
module ClassMethods # :nodoc:
|
21
|
-
def column_details
|
22
|
-
return @column_details if @column_details
|
23
|
-
|
24
|
-
@column_details = []
|
25
|
-
|
26
|
-
klass.columns.each do |column|
|
27
|
-
column_detail = {:column => column}
|
28
|
-
column_detail[:aliases] = case column.type
|
29
|
-
when :datetime, :time, :timestamp
|
30
|
-
[column.name.gsub(/_at$/, "")]
|
31
|
-
when :date
|
32
|
-
[column.name.gsub(/_at$/, "")]
|
33
|
-
else
|
34
|
-
[]
|
35
|
-
end
|
36
|
-
|
37
|
-
@column_details << column_detail
|
38
|
-
end
|
39
|
-
|
40
|
-
@column_details
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
module InstanceMethods # :nodoc:
|
45
|
-
def initialize_with_magic_methods(*args)
|
46
|
-
add_associations!
|
47
|
-
add_column_equals_conditions!
|
48
|
-
add_class_level_conditions!
|
49
|
-
initialize_without_magic_methods(*args)
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
def add_associations!
|
54
|
-
return true if self.class.added_associations
|
55
|
-
|
56
|
-
klass.reflect_on_all_associations.each do |association|
|
57
|
-
next if !association.options[:finder_sql].nil? # associations with finder_sql should not be added since conditions can not be chained to them, etc.
|
58
|
-
self.class.class_eval <<-"end_eval", __FILE__, __LINE__
|
59
|
-
def #{association.name}
|
60
|
-
return @#{association.name} unless @#{association.name}.nil?
|
61
|
-
@#{association.name} = Searchlogic::Conditions::Base.create_virtual_class(#{association.class_name}).new
|
62
|
-
@#{association.name}.object_name = :#{association.name}
|
63
|
-
@#{association.name}.protect = protect
|
64
|
-
objects << @#{association.name}
|
65
|
-
@#{association.name}
|
66
|
-
end
|
67
|
-
|
68
|
-
def #{association.name}=(conditions)
|
69
|
-
@conditions = nil
|
70
|
-
#{association.name}.conditions = conditions
|
71
|
-
end
|
72
|
-
|
73
|
-
def reset_#{association.name}!
|
74
|
-
objects.delete(#{association.name})
|
75
|
-
@#{association.name} = nil
|
76
|
-
end
|
77
|
-
end_eval
|
78
|
-
end
|
79
|
-
|
80
|
-
self.class.added_associations = true
|
81
|
-
end
|
82
|
-
|
83
|
-
def add_column_equals_conditions!
|
84
|
-
return true if self.class.added_column_equals_conditions
|
85
|
-
klass.column_names.each { |name| setup_condition(name) }
|
86
|
-
self.class.added_column_equals_conditions = true
|
87
|
-
end
|
88
|
-
|
89
|
-
def add_class_level_conditions!
|
90
|
-
return true if self.class.added_class_level_conditions
|
91
|
-
class_level_conditions = self.class.conditions.select { |condition_class| !condition_class.condition_names_for_model.blank? }
|
92
|
-
class_level_conditions.each do |condition_class|
|
93
|
-
condition_class.condition_names_for_model.each_with_index do |condition_name, index|
|
94
|
-
if index == 0
|
95
|
-
add_condition!(condition_class, condition_name, :column => klass.columns_hash[klass.primary_key])
|
96
|
-
else
|
97
|
-
add_condition_alias!(condition_name, condition_class.condition_names_for_model.first)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
self.class.added_class_level_conditions = true
|
102
|
-
end
|
103
|
-
|
104
|
-
def sanitize_method_name(name)
|
105
|
-
name.gsub("=", "").gsub(/^(and|or)_/, "")
|
106
|
-
end
|
107
|
-
|
108
|
-
def extract_column_and_condition_from_method_name(name)
|
109
|
-
name_parts = sanitize_method_name(name).split("_")
|
110
|
-
|
111
|
-
condition_parts = []
|
112
|
-
column = nil
|
113
|
-
while column.nil? && name_parts.size > 0
|
114
|
-
possible_column_name = name_parts.join("_")
|
115
|
-
|
116
|
-
self.class.column_details.each do |column_detail|
|
117
|
-
if column_detail[:column].name == possible_column_name || column_detail[:aliases].include?(possible_column_name)
|
118
|
-
column = column_detail
|
119
|
-
break
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
condition_parts << name_parts.pop if !column
|
124
|
-
end
|
125
|
-
|
126
|
-
return if column.nil?
|
127
|
-
|
128
|
-
condition_name = condition_parts.reverse.join("_")
|
129
|
-
condition = nil
|
130
|
-
|
131
|
-
# Find the real condition
|
132
|
-
self.class.conditions.each do |condition_klass|
|
133
|
-
if condition_klass.condition_names_for_column.include?(condition_name)
|
134
|
-
condition = condition_klass
|
135
|
-
break
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
[column, condition]
|
140
|
-
end
|
141
|
-
|
142
|
-
def breakdown_method_name(name)
|
143
|
-
column_detail, condition_klass = extract_column_and_condition_from_method_name(name)
|
144
|
-
if !column_detail.nil? && !condition_klass.nil?
|
145
|
-
# There were no modifiers
|
146
|
-
return [[], column_detail, condition_klass]
|
147
|
-
else
|
148
|
-
# There might be modifiers
|
149
|
-
name_parts = name.split("_of_")
|
150
|
-
column_detail, condition_klass = extract_column_and_condition_from_method_name(name_parts.pop)
|
151
|
-
if !column_detail.nil? && !condition_klass.nil?
|
152
|
-
# There were modifiers, lets get their real names
|
153
|
-
modifier_klasses = []
|
154
|
-
name_parts.each do |modifier_name|
|
155
|
-
size_before = modifier_klasses.size
|
156
|
-
self.class.modifiers.each do |modifier_klass|
|
157
|
-
if modifier_klass.modifier_names.include?(modifier_name)
|
158
|
-
modifier_klasses << modifier_klass
|
159
|
-
break
|
160
|
-
end
|
161
|
-
end
|
162
|
-
return if modifier_klasses.size == size_before # there was an invalid modifer, return nil for everything and let it act as a nomethoderror
|
163
|
-
end
|
164
|
-
|
165
|
-
return [modifier_klasses, column_detail, condition_klass]
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
nil
|
170
|
-
end
|
171
|
-
|
172
|
-
def build_method_name(modifier_klasses, column_name, condition_name)
|
173
|
-
modifier_name_parts = []
|
174
|
-
modifier_klasses.each { |modifier_klass| modifier_name_parts << modifier_klass.modifier_names.first }
|
175
|
-
method_name_parts = []
|
176
|
-
method_name_parts << modifier_name_parts.join("_of_") + "_of" unless modifier_name_parts.blank?
|
177
|
-
method_name_parts << column_name
|
178
|
-
method_name_parts << condition_name unless condition_name.blank?
|
179
|
-
method_name_parts.join("_").underscore
|
180
|
-
end
|
181
|
-
|
182
|
-
def method_missing_with_magic_methods(name, *args, &block)
|
183
|
-
if setup_condition(name)
|
184
|
-
send(name, *args, &block)
|
185
|
-
else
|
186
|
-
method_missing_without_magic_methods(name, *args, &block)
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
def setup_condition(name)
|
191
|
-
modifier_klasses, column_detail, condition_klass = breakdown_method_name(name.to_s)
|
192
|
-
if !column_detail.nil? && !condition_klass.nil?
|
193
|
-
method_name = build_method_name(modifier_klasses, column_detail[:column].name, condition_klass.condition_names_for_column.first)
|
194
|
-
|
195
|
-
if !added_condition?(method_name)
|
196
|
-
column_type = column_sql = nil
|
197
|
-
if !modifier_klasses.blank?
|
198
|
-
# Find the column type
|
199
|
-
column_type = modifier_klasses.first.return_type
|
200
|
-
|
201
|
-
# Build the column sql
|
202
|
-
column_sql = "{table}.{column}"
|
203
|
-
modifier_klasses.each do |modifier_klass|
|
204
|
-
next unless klass.connection.respond_to?(modifier_klass.adapter_method_name)
|
205
|
-
column_sql = klass.connection.send(modifier_klass.adapter_method_name, column_sql)
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
add_condition!(condition_klass, method_name, :column => column_detail[:column], :column_type => column_type, :column_sql_format => column_sql)
|
210
|
-
|
211
|
-
([column_detail[:column].name] + column_detail[:aliases]).each do |column_name|
|
212
|
-
condition_klass.condition_names_for_column.each do |condition_name|
|
213
|
-
alias_method_name = build_method_name(modifier_klasses, column_name, condition_name)
|
214
|
-
add_condition_alias!(alias_method_name, method_name) unless added_condition?(alias_method_name)
|
215
|
-
end
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
alias_method_name = sanitize_method_name(name.to_s)
|
220
|
-
add_condition_alias!(alias_method_name, method_name) unless added_condition?(alias_method_name)
|
221
|
-
|
222
|
-
return true
|
223
|
-
end
|
224
|
-
|
225
|
-
false
|
226
|
-
end
|
227
|
-
|
228
|
-
def add_condition!(condition, name, options = {})
|
229
|
-
options[:column] = options[:column].name if options[:column]
|
230
|
-
|
231
|
-
self.class.class_eval <<-"end_eval", __FILE__, __LINE__
|
232
|
-
def #{name}_object
|
233
|
-
return @#{name} unless @#{name}.nil?
|
234
|
-
@#{name} = #{condition.name}.new(klass, #{options.inspect})
|
235
|
-
@#{name}.object_name = :#{name}
|
236
|
-
objects << @#{name}
|
237
|
-
@#{name}
|
238
|
-
end
|
239
|
-
|
240
|
-
def #{name}
|
241
|
-
#{name}_object.value
|
242
|
-
end
|
243
|
-
alias_method :and_#{name}, :#{name}
|
244
|
-
alias_method :or_#{name}, :#{name}
|
245
|
-
|
246
|
-
def #{name}=(value)
|
247
|
-
@conditions = nil
|
248
|
-
#{name}_object.value = value
|
249
|
-
value
|
250
|
-
end
|
251
|
-
|
252
|
-
def and_#{name}=(value)
|
253
|
-
#{name}_object.explicit_any = false
|
254
|
-
self.#{name} = value
|
255
|
-
end
|
256
|
-
|
257
|
-
def or_#{name}=(value)
|
258
|
-
#{name}_object.explicit_any = true
|
259
|
-
self.#{name} = value
|
260
|
-
end
|
261
|
-
|
262
|
-
def reset_#{name}!
|
263
|
-
objects.delete(#{name}_object)
|
264
|
-
@#{name} = nil
|
265
|
-
end
|
266
|
-
end_eval
|
267
|
-
end
|
268
|
-
|
269
|
-
def added_condition?(name)
|
270
|
-
respond_to?("#{name}_object")
|
271
|
-
end
|
272
|
-
|
273
|
-
def add_condition_alias!(alias_name, name)
|
274
|
-
self.class.class_eval do
|
275
|
-
alias_method "#{alias_name}_object", "#{name}_object"
|
276
|
-
alias_method alias_name, name
|
277
|
-
alias_method "#{alias_name}=", "#{name}="
|
278
|
-
alias_method "and_#{alias_name}=", "and_#{name}="
|
279
|
-
alias_method "or_#{alias_name}=", "or_#{name}="
|
280
|
-
alias_method "reset_#{alias_name}!", "reset_#{name}!"
|
281
|
-
end
|
282
|
-
end
|
283
|
-
end
|
284
|
-
end
|
285
|
-
end
|
286
|
-
end
|