searchgasm 1.0.0 → 1.0.1
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/CHANGELOG.rdoc +64 -0
- data/Manifest +3 -1
- data/README.rdoc +19 -29
- data/lib/searchgasm/active_record/associations.rb +10 -1
- data/lib/searchgasm/active_record/base.rb +60 -10
- data/lib/searchgasm/active_record.rb +8 -0
- data/lib/searchgasm/conditions/base.rb +66 -19
- data/lib/searchgasm/core_ext/hash.rb +22 -0
- data/lib/searchgasm/helpers/control_types/links.rb +65 -31
- data/lib/searchgasm/helpers/control_types/select.rb +1 -1
- data/lib/searchgasm/helpers/control_types.rb +18 -2
- data/lib/searchgasm/helpers/form.rb +10 -4
- data/lib/searchgasm/helpers/utilities.rb +27 -2
- data/lib/searchgasm/helpers.rb +7 -1
- data/lib/searchgasm/search/base.rb +38 -9
- data/lib/searchgasm/search/conditions.rb +26 -6
- data/lib/searchgasm/search/ordering.rb +14 -3
- data/lib/searchgasm/search/pagination.rb +52 -7
- data/lib/searchgasm/search/protection.rb +25 -3
- data/lib/searchgasm/version.rb +1 -1
- data/lib/searchgasm.rb +3 -0
- data/searchgasm.gemspec +9 -5
- data/test/test_condition_base.rb +4 -0
- data/test/test_conditions_base.rb +10 -10
- data/test/test_search_base.rb +13 -9
- data/test/test_search_conditions.rb +2 -2
- data/test/test_search_ordering.rb +2 -2
- data/test/test_search_pagination.rb +3 -3
- metadata +8 -4
- data/CHANGELOG +0 -23
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
== 1.0.1 released 2008-09-08
|
2
|
+
|
3
|
+
* Cached "searchers" so when a new search object is instantiated it doesn't go through all of the meta programming and method creation. Helps a lot with performance. You will see the speed benefits after the first instantiation.
|
4
|
+
* Added in new options for page_links.
|
5
|
+
* Fixed minor bugs when doing page_links.
|
6
|
+
* Updated documentation to be more detailed and inclusive.
|
7
|
+
|
8
|
+
== 1.0.0 released 2008-09-08
|
9
|
+
|
10
|
+
* Major changes in the helpers, they were completely re-engineered. Hence the new version. I established a pattern between all helpers giving you complete flexibility as to how they are used. All helpers are called differently now (see documentation).
|
11
|
+
|
12
|
+
== 0.9.10 released 2008-09-08
|
13
|
+
|
14
|
+
* Fixed bug with setting the per_page configuration to only take effect on protected searches, thus staying out of the way of normal searching.
|
15
|
+
* Hardened more tests
|
16
|
+
|
17
|
+
== 0.9.9 released 2008-09-07
|
18
|
+
|
19
|
+
* Fixed setting per_page to nil, false, or ''. This is done to "show all" results.
|
20
|
+
|
21
|
+
== 0.9.8 released 2008-09-06
|
22
|
+
|
23
|
+
* Fixed order_by helper bug when guessing the text with arrays. Should use the first value instead of last.
|
24
|
+
* Added in per_page config option.
|
25
|
+
|
26
|
+
== 0.9.7 released 2008-09-06
|
27
|
+
|
28
|
+
* Complete class restructure. Moved the 3 main components into their own base level class: Search, Conditions, Condition
|
29
|
+
* Split logic and functionality into their own modules, implemented via alias_chain_method
|
30
|
+
* Added in helpers for using in a rails app
|
31
|
+
* Added link to documentation and live example in README
|
32
|
+
* Various small bug fixes
|
33
|
+
* Hardened tests
|
34
|
+
|
35
|
+
== 0.9.6 released 2008-09-04
|
36
|
+
|
37
|
+
* Fixed bug when instantiating with nil options
|
38
|
+
|
39
|
+
== 0.9.5 released 2008-09-03
|
40
|
+
|
41
|
+
* Enhanced searching with conditions only, added in search methods and calculations
|
42
|
+
* Updated README to include examples
|
43
|
+
|
44
|
+
== 0.9.4 released 2008-09-03
|
45
|
+
|
46
|
+
* Cleaned up search methods
|
47
|
+
* Removed reset!method for both searching and searching by conditions
|
48
|
+
|
49
|
+
== 0.9.3 released 2008-09-02
|
50
|
+
|
51
|
+
* Changed structure of conditions to have their own class
|
52
|
+
* Added API for adding your own conditions.
|
53
|
+
|
54
|
+
== 0.9.2 released 2008-09-02
|
55
|
+
|
56
|
+
* Enhanced protection from SQL injections (made more efficient)
|
57
|
+
|
58
|
+
== 0.9.1 released 2008-09-02
|
59
|
+
|
60
|
+
* Added aliases for datetime, date, time, and timestamp attrs. You could call created_at_after, now you can also call created_after. Just removed the "at" requirement.
|
61
|
+
|
62
|
+
== 0.9.0 released 2008-09-01
|
63
|
+
|
64
|
+
* First release
|
data/Manifest
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
CHANGELOG
|
1
|
+
CHANGELOG.rdoc
|
2
2
|
examples/README.rdoc
|
3
3
|
init.rb
|
4
4
|
lib/searchgasm/active_record/associations.rb
|
5
5
|
lib/searchgasm/active_record/base.rb
|
6
|
+
lib/searchgasm/active_record.rb
|
6
7
|
lib/searchgasm/condition/base.rb
|
7
8
|
lib/searchgasm/condition/begins_with.rb
|
8
9
|
lib/searchgasm/condition/child_of.rb
|
@@ -22,6 +23,7 @@ lib/searchgasm/condition/tree.rb
|
|
22
23
|
lib/searchgasm/conditions/base.rb
|
23
24
|
lib/searchgasm/conditions/protection.rb
|
24
25
|
lib/searchgasm/config.rb
|
26
|
+
lib/searchgasm/core_ext/hash.rb
|
25
27
|
lib/searchgasm/helpers/control_types/link.rb
|
26
28
|
lib/searchgasm/helpers/control_types/links.rb
|
27
29
|
lib/searchgasm/helpers/control_types/remote_link.rb
|
data/README.rdoc
CHANGED
@@ -8,7 +8,7 @@ Searchgasm is orgasmic. Maybe not orgasmic, but you will get aroused. So go grab
|
|
8
8
|
|
9
9
|
* <b>Documentation:</b> http://searchgasm.rubyforge.org
|
10
10
|
* <b>Easy pagination, ordering, and searching tutorial:</b> http://www.binarylogic.com/2008/9/7/tutorial-pagination-ordering-and-searching-with-searchgasm
|
11
|
-
* <b>
|
11
|
+
* <b>Live example of the tutorial above (with source):</b> http://searchgasm_example.binarylogic.com
|
12
12
|
|
13
13
|
== Install and use
|
14
14
|
|
@@ -67,8 +67,8 @@ Now your view. Things to note in this view:
|
|
67
67
|
|
68
68
|
1. Passing a search object right into form\_for and fields\_for
|
69
69
|
2. The built in conditions for each column and how you can traverse the relationships and set conditions on them
|
70
|
-
3. The
|
71
|
-
4. The
|
70
|
+
3. The order_by_link helper
|
71
|
+
4. The page_select and per_page_select helpers
|
72
72
|
5. All of your search logic is in 1 spot: your view. Nice and DRY.
|
73
73
|
|
74
74
|
Your view:
|
@@ -82,25 +82,28 @@ Your view:
|
|
82
82
|
= orders.select :total_gt, (1..100)
|
83
83
|
= f.submit "Search"
|
84
84
|
|
85
|
-
|
86
|
-
%
|
87
|
-
%
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
85
|
+
- if @users_count > 0
|
86
|
+
%table
|
87
|
+
%tr
|
88
|
+
%th= order_by_link :account => :name
|
89
|
+
%th= order_by_link :first_name
|
90
|
+
%th= order_by_link :last_name
|
91
|
+
%th= order_by_link :email
|
92
|
+
- @users.each do |user|
|
92
93
|
%tr
|
93
94
|
%td= user.account? ? user.account.name : "-"
|
94
95
|
%td= user.first_name
|
95
96
|
%td= user.last_name
|
96
97
|
%td= user.email
|
97
98
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
99
|
+
Per page:
|
100
|
+
= per_page_select
|
101
|
+
Page:
|
102
|
+
= page_select
|
103
|
+
- else
|
104
|
+
No users were found.
|
102
105
|
|
103
|
-
<b>
|
106
|
+
<b>See my tutorial on this example: http://www.binarylogic.com/2008/9/7/tutorial-pagination-ordering-and-searching-with-searchgasm</b>
|
104
107
|
|
105
108
|
== Exhaustive Example w/ Object Based Searching (great for form_for or fields_for)
|
106
109
|
|
@@ -174,13 +177,6 @@ Any of the options used in the above example can be used in these, but for the s
|
|
174
177
|
search.per_page = 20
|
175
178
|
search.all
|
176
179
|
|
177
|
-
If you want to use Searchgasm directly:
|
178
|
-
|
179
|
-
search = Searchgasm::Search::Base.new(User, :conditions => {:age_gt => 18})
|
180
|
-
search.conditions.first_name_contains = "Ben"
|
181
|
-
search.per_page = 20
|
182
|
-
search.all
|
183
|
-
|
184
180
|
== Search with conditions only
|
185
181
|
|
186
182
|
Don't need pagination, ordering, or any of the other options? Search with conditions only.
|
@@ -194,19 +190,13 @@ Pass a conditions object right into ActiveRecord:
|
|
194
190
|
|
195
191
|
User.all(:conditions => conditions)
|
196
192
|
|
197
|
-
Again, if you want to use Searchgasm directly:
|
198
|
-
|
199
|
-
conditions = Searchgasm::Conditions::Base.new(User, :age_gt => 18)
|
200
|
-
conditions.first_name_contains = "Ben"
|
201
|
-
conditions.all
|
202
|
-
|
203
193
|
== Scoped searching
|
204
194
|
|
205
195
|
@current_user.orders.find(:all, :conditions => {:total_lte => 500})
|
206
196
|
@current_user.orders.count(:conditions => {:total_lte => 500})
|
207
197
|
@current_user.orders.sum('total', :conditions => {:total_lte => 500})
|
208
198
|
|
209
|
-
search = @current_user.orders.build_search(
|
199
|
+
search = @current_user.orders.build_search(:conditions => {:total_lte => 500})
|
210
200
|
|
211
201
|
== Searching trees
|
212
202
|
|
@@ -1,31 +1,39 @@
|
|
1
1
|
module Searchgasm
|
2
2
|
module ActiveRecord
|
3
|
+
# = Searchgasm ActiveRecord Associations
|
4
|
+
#
|
5
|
+
# These methods hook into ActiveRecords association methods and add in searchgasm functionality.
|
3
6
|
module Associations
|
4
7
|
module AssociationCollection
|
8
|
+
# This is an alias method chain. It hook into ActiveRecord's "find" method for associations and checks to see if Searchgasm should get involved.
|
5
9
|
def find_with_searchgasm(*args)
|
6
10
|
options = args.extract_options!
|
7
11
|
args << sanitize_options_with_searchgasm(options)
|
8
12
|
find_without_searchgasm(*args)
|
9
13
|
end
|
10
14
|
|
15
|
+
# See build_conditions under Searchgasm::ActiveRecord::Base. This is the same thing but for associations.
|
11
16
|
def build_conditions(options = {}, &block)
|
12
17
|
conditions = @reflection.klass.build_conditions(options, &block)
|
13
18
|
conditions.scope = scope(:find)[:conditions]
|
14
19
|
conditions
|
15
20
|
end
|
16
21
|
|
22
|
+
# See build_conditions! under Searchgasm::ActiveRecord::Base. This is the same thing but for associations.
|
17
23
|
def build_conditions!(options = {}, &block)
|
18
24
|
conditions = @reflection.klass.build_conditions!(options, &block)
|
19
25
|
conditions.scope = scope(:find)[:conditions]
|
20
26
|
conditions
|
21
27
|
end
|
22
|
-
|
28
|
+
|
29
|
+
# See build_search under Searchgasm::ActiveRecord::Base. This is the same thing but for associations.
|
23
30
|
def build_search(options = {}, &block)
|
24
31
|
conditions = @reflection.klass.build_search(options, &block)
|
25
32
|
conditions.scope = scope(:find)[:conditions]
|
26
33
|
conditions
|
27
34
|
end
|
28
35
|
|
36
|
+
# See build_conditions! under Searchgasm::ActiveRecord::Base. This is the same thing but for associations.
|
29
37
|
def build_search!(options = {}, &block)
|
30
38
|
conditions = @reflection.klass.build_search!(options, &block)
|
31
39
|
conditions.scope = scope(:find)[:conditions]
|
@@ -34,6 +42,7 @@ module Searchgasm
|
|
34
42
|
end
|
35
43
|
|
36
44
|
module HasManyAssociation
|
45
|
+
# This is an alias method chain. It hook into ActiveRecord's "calculate" method for has many associations and checks to see if Searchgasm should get involved.
|
37
46
|
def count_with_searchgasm(*args)
|
38
47
|
column_name, options = @reflection.klass.send(:construct_count_options_from_args, *args)
|
39
48
|
count_without_searchgasm(column_name, sanitize_options_with_searchgasm(options))
|
@@ -1,13 +1,17 @@
|
|
1
1
|
module Searchgasm
|
2
|
-
module ActiveRecord
|
2
|
+
module ActiveRecord
|
3
|
+
# = Searchgasm ActiveRecord Base
|
4
|
+
# Adds in base level functionality to ActiveRecord
|
3
5
|
module Base
|
6
|
+
# This is an alias method chain. It hook into ActiveRecord's "calculate" method and checks to see if Searchgasm should get involved.
|
4
7
|
def calculate_with_searchgasm(*args)
|
5
8
|
options = args.extract_options!
|
6
9
|
options = sanitize_options_with_searchgasm(options)
|
7
10
|
args << options
|
8
11
|
calculate_without_searchgasm(*args)
|
9
12
|
end
|
10
|
-
|
13
|
+
|
14
|
+
# This is an alias method chain. It hooks into ActiveRecord's "find" method and checks to see if Searchgasm should get involved.
|
11
15
|
def find_with_searchgasm(*args)
|
12
16
|
options = args.extract_options!
|
13
17
|
options = sanitize_options_with_searchgasm(options)
|
@@ -15,12 +19,31 @@ module Searchgasm
|
|
15
19
|
find_without_searchgasm(*args)
|
16
20
|
end
|
17
21
|
|
22
|
+
# This is an alias method chain. It hooks into ActiveRecord's scopes and checks to see if Searchgasm should get involved. Allowing you to use all of Searchgasms conditions and tools
|
23
|
+
# in scopes as well.
|
24
|
+
#
|
25
|
+
# === Examples
|
26
|
+
#
|
27
|
+
# named_scope :top_expensive, :conditions => {:total_gt => 1_000_000}, :per_page => 10
|
28
|
+
#
|
29
|
+
# with_scope(:find => {:conditions => {:total_gt => 1_000_000}, :per_page => 10}) do
|
30
|
+
# find(:all)
|
31
|
+
# end
|
18
32
|
def scope_with_searchgasm(method, key = nil)
|
19
33
|
scope = scope_without_searchgasm(method, key)
|
20
34
|
return sanitize_options_with_searchgasm(scope) if key.nil? && method == :find && !scope.blank?
|
21
35
|
scope
|
22
36
|
end
|
23
|
-
|
37
|
+
|
38
|
+
# This is a special method that Searchgasm adds in. It returns a new conditions object on the model. So you can search by conditions *only*.
|
39
|
+
#
|
40
|
+
# <b>This method is "protected". Meaning it checks the passed options for SQL injections. So trying to write raw SQL in *any* of the option will result in a raised exception. It's safe to pass a params object when instantiating.</b>
|
41
|
+
#
|
42
|
+
# === Examples
|
43
|
+
#
|
44
|
+
# conditions = User.new_conditions
|
45
|
+
# conditions.first_name_contains = "Ben"
|
46
|
+
# conditions.all # can call any search method: first, find(:all), find(:first), sum("id"), etc...
|
24
47
|
def build_conditions(values = {}, &block)
|
25
48
|
conditions = searchgasm_conditions
|
26
49
|
conditions.protect = true
|
@@ -28,13 +51,28 @@ module Searchgasm
|
|
28
51
|
yield conditions if block_given?
|
29
52
|
conditions
|
30
53
|
end
|
31
|
-
|
54
|
+
|
55
|
+
# See build_conditions. This is the same method but *without* protection. Do *NOT* pass in a params object to this method.
|
32
56
|
def build_conditions!(values = {}, &block)
|
33
57
|
conditions = searchgasm_conditions(values)
|
34
58
|
yield conditions if block_given?
|
35
59
|
conditions
|
36
60
|
end
|
37
|
-
|
61
|
+
|
62
|
+
# This is a special method that Searchgasm adds in. It returns a new search object on the model. So you can search via an object.
|
63
|
+
#
|
64
|
+
# <b>This method is "protected". Meaning it checks the passed options for SQL injections. So trying to write raw SQL in *any* of the option will result in a raised exception. It's safe to pass a params object when instantiating.</b>
|
65
|
+
#
|
66
|
+
# This method has an alias "new_search"
|
67
|
+
#
|
68
|
+
# === Examples
|
69
|
+
#
|
70
|
+
# search = User.new_search
|
71
|
+
# search.conditions.first_name_contains = "Ben"
|
72
|
+
# search.per_page = 20
|
73
|
+
# search.page = 2
|
74
|
+
# search.order_by = {:user_group => :name}
|
75
|
+
# search.all # can call any search method: first, find(:all), find(:first), sum("id"), etc...
|
38
76
|
def build_search(options = {}, &block)
|
39
77
|
search = searchgasm_searcher
|
40
78
|
search.protect = true
|
@@ -42,26 +80,38 @@ module Searchgasm
|
|
42
80
|
yield search if block_given?
|
43
81
|
search
|
44
82
|
end
|
45
|
-
|
83
|
+
|
84
|
+
# See build_search. This is the same method but *without* protection. Do *NOT* pass in a params object to this method.
|
85
|
+
#
|
86
|
+
# This also has an alias "new_search!"
|
46
87
|
def build_search!(options = {}, &block)
|
47
88
|
search = searchgasm_searcher(options)
|
48
89
|
yield search if block_given?
|
49
90
|
search
|
50
91
|
end
|
51
92
|
|
93
|
+
# Similar to ActiveRecord's attr_protected, but for conditions. It will block any conditions in this array that are being mass assigned. Mass assignments are:
|
94
|
+
#
|
95
|
+
# === Examples
|
96
|
+
#
|
97
|
+
# search = User.new_search(:conditions => {:first_name_like => "Ben", :email_contains => "binarylogic.com"})
|
98
|
+
# search.options = {:conditions => {:first_name_like => "Ben", :email_contains => "binarylogic.com"}}
|
99
|
+
#
|
100
|
+
# If first_name_like is in the list of conditions_protected then it will be removed from the hash.
|
52
101
|
def conditions_protected(*conditions)
|
53
102
|
write_inheritable_attribute(:conditions_protected, Set.new(conditions.map(&:to_s)) + (protected_conditions || []))
|
54
103
|
end
|
55
104
|
|
56
|
-
def protected_conditions
|
105
|
+
def protected_conditions # :nodoc:
|
57
106
|
read_inheritable_attribute(:conditions_protected)
|
58
107
|
end
|
59
108
|
|
109
|
+
# This is the reverse of conditions_protected. You can specify conditions here and *only* these conditions will be allowed in mass assignment. Any condition not specified here will be blocked.
|
60
110
|
def conditions_accessible(*conditions)
|
61
111
|
write_inheritable_attribute(:conditions_accessible, Set.new(conditions.map(&:to_s)) + (protected_conditions || []))
|
62
112
|
end
|
63
113
|
|
64
|
-
def accessible_conditions
|
114
|
+
def accessible_conditions # :nodoc:
|
65
115
|
read_inheritable_attribute(:conditions_accessible)
|
66
116
|
end
|
67
117
|
|
@@ -72,11 +122,11 @@ module Searchgasm
|
|
72
122
|
end
|
73
123
|
|
74
124
|
def searchgasm_conditions(options = {})
|
75
|
-
Searchgasm::Conditions::Base.new(
|
125
|
+
Searchgasm::Conditions::Base.create_virtual_class(self).new(options)
|
76
126
|
end
|
77
127
|
|
78
128
|
def searchgasm_searcher(options = {})
|
79
|
-
Searchgasm::Search::Base.new(
|
129
|
+
Searchgasm::Search::Base.create_virtual_class(self).new(options)
|
80
130
|
end
|
81
131
|
end
|
82
132
|
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
# == Searchgasm ActiveRecord
|
3
|
+
#
|
4
|
+
# Hooks into ActiveRecord to add all of the searchgasm functionality into your models. Only uses what is publically available, doesn't dig into internals, and
|
5
|
+
# searchgasm only gets involved when needed.
|
6
|
+
module ActiveRecord
|
7
|
+
end
|
8
|
+
end
|
@@ -7,9 +7,11 @@ module Searchgasm
|
|
7
7
|
class Base
|
8
8
|
include Utilities
|
9
9
|
|
10
|
-
attr_accessor :
|
10
|
+
attr_accessor :relationship_name, :scope
|
11
11
|
|
12
12
|
class << self
|
13
|
+
attr_accessor :added_klass_conditions, :added_column_conditions, :added_associations
|
14
|
+
|
13
15
|
# Registers a condition as an available condition for a column or a class.
|
14
16
|
#
|
15
17
|
# === Example
|
@@ -40,9 +42,9 @@ module Searchgasm
|
|
40
42
|
# end
|
41
43
|
#
|
42
44
|
# Searchgasm::Seearch::Conditions.register_condition(SoundsLikeCondition)
|
43
|
-
def register_condition(
|
44
|
-
raise(ArgumentError, "You can only register conditions that extend Searchgasm::Condition::Base") unless
|
45
|
-
conditions <<
|
45
|
+
def register_condition(condition_class)
|
46
|
+
raise(ArgumentError, "You can only register conditions that extend Searchgasm::Condition::Base") unless condition_class.ancestors.include?(Searchgasm::Condition::Base)
|
47
|
+
conditions << condition_class unless conditions.include?(condition_class)
|
46
48
|
end
|
47
49
|
|
48
50
|
# A list of available condition type classes
|
@@ -50,19 +52,50 @@ module Searchgasm
|
|
50
52
|
@@conditions ||= []
|
51
53
|
end
|
52
54
|
|
53
|
-
|
55
|
+
# A list of all associations created, used for caching and performance
|
56
|
+
def association_names
|
57
|
+
@association_names ||= []
|
58
|
+
end
|
59
|
+
|
60
|
+
# A list of all conditions available, users for caching and performance
|
61
|
+
def condition_names
|
62
|
+
@condition_names ||= []
|
63
|
+
end
|
64
|
+
|
65
|
+
def needed?(model_class, conditions) # :nodoc:
|
54
66
|
if conditions.is_a?(Hash)
|
55
67
|
conditions.stringify_keys.keys.each do |condition|
|
56
|
-
return true unless
|
68
|
+
return true unless model_class.column_names.include?(condition)
|
57
69
|
end
|
58
70
|
end
|
59
71
|
|
60
72
|
false
|
61
73
|
end
|
74
|
+
|
75
|
+
# Creates virtual classes for the class passed to it. This is a neccesity for keeping dynamically created method
|
76
|
+
# names specific to models. It provides caching and helps a lot with performance.
|
77
|
+
def create_virtual_class(model_class)
|
78
|
+
class_search_name = "::#{model_class.name}Conditions"
|
79
|
+
|
80
|
+
begin
|
81
|
+
class_search_name.constantize
|
82
|
+
rescue NameError
|
83
|
+
eval <<-end_eval
|
84
|
+
class #{class_search_name} < ::Searchgasm::Conditions::Base; end;
|
85
|
+
end_eval
|
86
|
+
|
87
|
+
class_search_name.constantize
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# The class / model we are searching
|
92
|
+
def klass
|
93
|
+
# Can't cache this because thin and mongrel don't play nice with caching constants
|
94
|
+
name.split("::").last.gsub(/Conditions$/, "").constantize
|
95
|
+
end
|
62
96
|
end
|
63
97
|
|
64
|
-
def initialize(
|
65
|
-
self.klass = klass
|
98
|
+
def initialize(init_conditions = {})
|
66
99
|
add_klass_conditions!
|
67
100
|
add_column_conditions!
|
68
101
|
add_associations!
|
@@ -90,6 +123,10 @@ module Searchgasm
|
|
90
123
|
i.blank? ? nil : (i.size == 1 ? i.first : i)
|
91
124
|
end
|
92
125
|
|
126
|
+
def klass
|
127
|
+
self.class.klass
|
128
|
+
end
|
129
|
+
|
93
130
|
# Sanitizes the conditions down into conditions that ActiveRecord::Base.find can understand.
|
94
131
|
def sanitize
|
95
132
|
conditions = merge_conditions(*objects.collect { |object| object.sanitize })
|
@@ -128,11 +165,15 @@ module Searchgasm
|
|
128
165
|
|
129
166
|
private
|
130
167
|
def add_associations!
|
168
|
+
return true if self.class.added_associations
|
169
|
+
|
131
170
|
klass.reflect_on_all_associations.each do |association|
|
171
|
+
self.class.association_names << association.name.to_s
|
172
|
+
|
132
173
|
self.class.class_eval <<-"end_eval", __FILE__, __LINE__
|
133
174
|
def #{association.name}
|
134
175
|
if @#{association.name}.nil?
|
135
|
-
@#{association.name} =
|
176
|
+
@#{association.name} = #{association.class_name}.new_conditions
|
136
177
|
@#{association.name}.relationship_name = "#{association.name}"
|
137
178
|
objects << @#{association.name}
|
138
179
|
end
|
@@ -143,9 +184,13 @@ module Searchgasm
|
|
143
184
|
def reset_#{association.name}!; objects.delete(#{association.name}); @#{association.name} = nil; end
|
144
185
|
end_eval
|
145
186
|
end
|
187
|
+
|
188
|
+
self.class.added_associations = true
|
146
189
|
end
|
147
190
|
|
148
191
|
def add_column_conditions!
|
192
|
+
return true if self.class.added_column_conditions
|
193
|
+
|
149
194
|
klass.columns.each do |column|
|
150
195
|
self.class.conditions.each do |condition_klass|
|
151
196
|
name = condition_klass.name_for_column(column)
|
@@ -154,10 +199,13 @@ module Searchgasm
|
|
154
199
|
condition_klass.aliases_for_column(column).each { |alias_name| add_condition_alias!(alias_name, name) }
|
155
200
|
end
|
156
201
|
end
|
202
|
+
|
203
|
+
self.class.added_column_conditions = true
|
157
204
|
end
|
158
205
|
|
159
206
|
def add_condition!(condition, name, column = nil)
|
160
|
-
condition_names << name
|
207
|
+
self.class.condition_names << name
|
208
|
+
|
161
209
|
self.class.class_eval <<-"end_eval", __FILE__, __LINE__
|
162
210
|
def #{name}_object
|
163
211
|
if @#{name}.nil?
|
@@ -174,7 +222,8 @@ module Searchgasm
|
|
174
222
|
end
|
175
223
|
|
176
224
|
def add_condition_alias!(alias_name, name)
|
177
|
-
condition_names << alias_name
|
225
|
+
self.class.condition_names << alias_name
|
226
|
+
|
178
227
|
self.class.class_eval do
|
179
228
|
alias_method alias_name, name
|
180
229
|
alias_method "#{alias_name}=", "#{name}="
|
@@ -182,26 +231,24 @@ module Searchgasm
|
|
182
231
|
end
|
183
232
|
|
184
233
|
def add_klass_conditions!
|
234
|
+
return true if self.class.added_klass_conditions
|
235
|
+
|
185
236
|
self.class.conditions.each do |condition|
|
186
237
|
name = condition.name_for_klass(klass)
|
187
238
|
next if name.blank?
|
188
239
|
add_condition!(condition, name)
|
189
240
|
condition.aliases_for_klass(klass).each { |alias_name| add_condition_alias!(alias_name, name) }
|
190
241
|
end
|
242
|
+
|
243
|
+
self.class.added_klass_conditions = true
|
191
244
|
end
|
192
245
|
|
193
246
|
def assert_valid_conditions(conditions)
|
194
|
-
|
195
|
-
keys += klass.reflect_on_all_associations.collect { |association| association.name }
|
196
|
-
conditions.symbolize_keys.assert_valid_keys(keys)
|
247
|
+
conditions.stringify_keys.assert_valid_keys(self.class.condition_names + self.class.association_names)
|
197
248
|
end
|
198
249
|
|
199
250
|
def associations
|
200
|
-
objects.select { |object| object.
|
201
|
-
end
|
202
|
-
|
203
|
-
def condition_names
|
204
|
-
@condition_names ||= []
|
251
|
+
objects.select { |object| object.class < ::Searchgasm::Conditions::Base }
|
205
252
|
end
|
206
253
|
|
207
254
|
def objects
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Searchgasm
|
2
|
+
module CoreExt # :nodoc: all
|
3
|
+
module Hash
|
4
|
+
def deep_dup
|
5
|
+
new_hash = {}
|
6
|
+
|
7
|
+
self.each do |k, v|
|
8
|
+
case v
|
9
|
+
when Hash
|
10
|
+
new_hash[k] = v.deep_dup
|
11
|
+
else
|
12
|
+
new_hash[k] = v
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
new_hash
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Hash.send(:include, Searchgasm::CoreExt::Hash)
|