searchlogic 1.5.4 → 1.5.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +13 -0
- data/Manifest +7 -1
- data/README.rdoc +78 -11
- data/Rakefile +15 -11
- data/lib/searchlogic/condition/base.rb +5 -1
- data/lib/searchlogic/condition/keywords.rb +2 -2
- data/lib/searchlogic/conditions/any_or_all.rb +42 -0
- data/lib/searchlogic/conditions/base.rb +36 -312
- data/lib/searchlogic/conditions/groups.rb +37 -0
- data/lib/searchlogic/conditions/magic_methods.rb +268 -0
- data/lib/searchlogic/conditions/protection.rb +1 -1
- data/lib/searchlogic/config/helpers.rb +77 -28
- data/lib/searchlogic/helpers/control_types/links.rb +1 -0
- data/lib/searchlogic/helpers/form.rb +1 -1
- data/lib/searchlogic/shared/utilities.rb +9 -2
- data/lib/searchlogic/version.rb +1 -1
- data/lib/searchlogic.rb +6 -0
- data/searchlogic.gemspec +9 -7
- data/test/active_record_tests/base_test.rb +13 -13
- data/test/condition_tests/{keyswords_test.rb → keywords_test.rb} +4 -0
- data/test/conditions_tests/any_or_all_test.rb +23 -0
- data/test/conditions_tests/base_test.rb +45 -88
- data/test/conditions_tests/groups_test.rb +51 -0
- data/test/conditions_tests/magic_methods_test.rb +24 -0
- data/test/search_tests/base_test.rb +7 -3
- data/test/test_helper.rb +12 -28
- metadata +17 -5
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
== 1.5.6 released 2008-11-17
|
2
|
+
|
3
|
+
* The order conditions are set is now relevant and will be reflected in the SQL. Setting a condition first will make it first in the SQL, setting a condition last will make it last in the SQL.
|
4
|
+
* The above allows for prefixing any condition with and_ or or_. Thus letting you create somewhat more complex queries, since the order matters.
|
5
|
+
* Added ability to group conditions to mimic parenthesis in raw SQL.
|
6
|
+
* Major clean up in the Searchlogic::Conditions name space: faster, smaller, cleaner, and modular.
|
7
|
+
|
8
|
+
== 1.5.5 released 2008-11-17
|
9
|
+
|
10
|
+
* Cleaned up class_name configuration for helpers, so that setting them to nil disables the class name
|
11
|
+
* Added page_links_div_wrapper and page_links_div_wrapper_class_name configuration option to add an wrapping div around page_links
|
12
|
+
* Added page_links_act_like_will_paginate configuration option to help with the transition from will_paginate
|
13
|
+
|
1
14
|
== 1.5.4 released 2008-11-16
|
2
15
|
|
3
16
|
* Removed subclass requirement for adding conditions in Conditions::Base
|
data/Manifest
CHANGED
@@ -29,7 +29,10 @@ lib/searchlogic/condition/not_like.rb
|
|
29
29
|
lib/searchlogic/condition/not_nil.rb
|
30
30
|
lib/searchlogic/condition/sibling_of.rb
|
31
31
|
lib/searchlogic/condition/tree.rb
|
32
|
+
lib/searchlogic/conditions/any_or_all.rb
|
32
33
|
lib/searchlogic/conditions/base.rb
|
34
|
+
lib/searchlogic/conditions/groups.rb
|
35
|
+
lib/searchlogic/conditions/magic_methods.rb
|
33
36
|
lib/searchlogic/conditions/protection.rb
|
34
37
|
lib/searchlogic/config/helpers.rb
|
35
38
|
lib/searchlogic/config/search.rb
|
@@ -109,7 +112,7 @@ test/condition_tests/equals_test.rb
|
|
109
112
|
test/condition_tests/greater_than_or_equal_to_test.rb
|
110
113
|
test/condition_tests/greater_than_test.rb
|
111
114
|
test/condition_tests/inclusive_descendant_of_test.rb
|
112
|
-
test/condition_tests/
|
115
|
+
test/condition_tests/keywords_test.rb
|
113
116
|
test/condition_tests/less_than_or_equal_to_test.rb
|
114
117
|
test/condition_tests/less_than_test.rb
|
115
118
|
test/condition_tests/like_test.rb
|
@@ -122,7 +125,10 @@ test/condition_tests/not_have_keywords_test.rb
|
|
122
125
|
test/condition_tests/not_like_test.rb
|
123
126
|
test/condition_tests/not_nil_test.rb
|
124
127
|
test/condition_tests/sibling_of_test.rb
|
128
|
+
test/conditions_tests/any_or_all_test.rb
|
125
129
|
test/conditions_tests/base_test.rb
|
130
|
+
test/conditions_tests/groups_test.rb
|
131
|
+
test/conditions_tests/magic_methods_test.rb
|
126
132
|
test/conditions_tests/protection_test.rb
|
127
133
|
test/config_test.rb
|
128
134
|
test/fixtures/accounts.yml
|
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= Searchlogic
|
2
2
|
|
3
|
-
Searchlogic is object based ActiveRecord searching, ordering, and pagination all in one.
|
3
|
+
Searchlogic is object based ActiveRecord searching, ordering, and pagination all in one. It's a simple, quick, all inclusive package for displaying data in your application.
|
4
4
|
|
5
5
|
== Helpful links
|
6
6
|
|
@@ -13,12 +13,12 @@ Searchlogic is object based ActiveRecord searching, ordering, and pagination all
|
|
13
13
|
|
14
14
|
sudo gem install searchlogic
|
15
15
|
|
16
|
-
For rails
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
For rails, as a gem (recommended)
|
17
|
+
|
18
|
+
# config/environment.rb
|
19
|
+
config.gem "searchlogic"
|
20
20
|
|
21
|
-
Or as a plugin
|
21
|
+
Or as a plugin (for older versions of rails)
|
22
22
|
|
23
23
|
script/plugin install git://github.com/binarylogic/searchlogic.git
|
24
24
|
|
@@ -178,17 +178,84 @@ Any of the options used in the above example can be used in these, but for the s
|
|
178
178
|
search.per_page = 20
|
179
179
|
search.all
|
180
180
|
|
181
|
+
search = User.new_search(:conditions => {:age_gt => 18}) do |s|
|
182
|
+
s.conditions.first_name_contains = "Ben"
|
183
|
+
s.per_page = 20
|
184
|
+
end
|
185
|
+
search.all
|
186
|
+
|
181
187
|
== Match ANY or ALL of the conditions
|
182
188
|
|
183
189
|
As you saw above, the nice thing about Searchlogic is it's integration with forms. I designed the "any" option so that forms can set this as well, just like a condition.
|
184
190
|
|
185
|
-
@search = User.new_search(:conditions => {:age_gt => 18})
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
end
|
191
|
+
@search = User.new_search(:conditions => {:age_gt => 18})
|
192
|
+
@search.conditions.first_name_contains = "Ben"
|
193
|
+
@search.conditions.any = true # can set this to "true" or "1" or "yes"
|
194
|
+
@search.all # will join all conditions with "or" instead of "and"
|
190
195
|
# ... all operations above are available
|
191
196
|
|
197
|
+
What if you want to mix and match?
|
198
|
+
|
199
|
+
@search = User.new_search(:conditions => {:age_gt => 18})
|
200
|
+
@search.conditions.or_first_name_contains = "Ben"
|
201
|
+
@search.conditions.or_last_name_contains = "Johnson"
|
202
|
+
@search.conditions.and_id_gt = 5 # the and_ is optional, calling just id_gt is the same thing
|
203
|
+
@search.all # will join conditions in the orders they were set with their specified join condition
|
204
|
+
# => age > 17 OR first_name like '%Ben%' OR lsat_name like '%Johnson%' AND id > 5
|
205
|
+
|
206
|
+
The order the conditions is set is relevant, as the SQL will be built in the same order.
|
207
|
+
|
208
|
+
== Grouping conditions
|
209
|
+
|
210
|
+
In more complex searching situations you might want to group conditions. Just like you use parenthesis in raw SQL. Searchlogic's "group" function is basically a way to implement parenthesis in your conditions. It's simple:
|
211
|
+
|
212
|
+
Group off an object:
|
213
|
+
|
214
|
+
search = User.new_search
|
215
|
+
search.id_gt = 2
|
216
|
+
group1 = search.conditions.group
|
217
|
+
group.first_name_like = "Ben"
|
218
|
+
group2 = search.conditions.group
|
219
|
+
group.last_name_like = "Johnson"
|
220
|
+
group21 = group2.group
|
221
|
+
group21.email_ends_with = "binarylogic.com"
|
222
|
+
# => id > 2 AND (first_name like '%Ben%') AND (last_name like '%Johnson%' AND (email like '%binarylogic.com'))
|
223
|
+
|
224
|
+
Group with a block:
|
225
|
+
|
226
|
+
search = User.new_search
|
227
|
+
search.id_gt = 2
|
228
|
+
search.conditions.group do |group|
|
229
|
+
group.first_name_like = "Ben"
|
230
|
+
end
|
231
|
+
search.conditions.group do |group|
|
232
|
+
group.last_name_like = "Johnson"
|
233
|
+
group.group do |sub_group|
|
234
|
+
sub_group.email_ends_with = "binarylogic.com"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
# => id > 2 AND (first_name like '%Ben%') AND (last_name like '%Johnson%' AND (email like '%binarylogic.com'))
|
238
|
+
|
239
|
+
Group with a hash:
|
240
|
+
|
241
|
+
search = User.new_search(:conditions => {
|
242
|
+
:id_gt => 2,
|
243
|
+
:group => [
|
244
|
+
{:first_name_like => "Ben"},
|
245
|
+
{
|
246
|
+
:last_name_like => "Johnson",
|
247
|
+
:group => {:email_ends_with => "binarylogic.com"}
|
248
|
+
}
|
249
|
+
]
|
250
|
+
})
|
251
|
+
# => id > 2 AND (first_name like '%Ben%') AND (last_name like '%Johnson%' AND (email like '%binarylogic.com'))
|
252
|
+
|
253
|
+
I want to end this by saying Searchlog was never meant to replace SQL, name_scopes, etc. If you need to perform complex searching there is nothing wrong with resorting to a named scope or using the traditional search methods. In fact, search logic plays nice with named_scopes anyways, so you can combine the 2 if needed:
|
254
|
+
|
255
|
+
@search = User.my_awesome_scope.another_cool_scope.new_search
|
256
|
+
|
257
|
+
The only reason I added this was to allow searchlogic to extend a little further into those advanced searches. If you need to scope conditions by using parenthesis, etc. you should resort to named_scopes or the traditional search method.
|
258
|
+
|
192
259
|
== Scoped searching
|
193
260
|
|
194
261
|
@current_user.orders.find(:all, :conditions => {:total_lte => 500})
|
data/Rakefile
CHANGED
@@ -1,15 +1,19 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'echoe'
|
3
|
-
|
4
2
|
require File.dirname(__FILE__) << "/lib/searchlogic/version"
|
5
3
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
4
|
+
begin
|
5
|
+
require 'echoe'
|
6
|
+
|
7
|
+
Echoe.new 'searchlogic' do |p|
|
8
|
+
p.version = Searchlogic::Version::STRING
|
9
|
+
p.author = "Ben Johnson of Binary Logic"
|
10
|
+
p.email = 'bjohnson@binarylogic.com'
|
11
|
+
p.project = 'searchlogic'
|
12
|
+
p.summary = "Object based ActiveRecord searching, ordering, pagination, and more!"
|
13
|
+
p.url = "http://github.com/binarylogic/searchlogic"
|
14
|
+
p.dependencies = %w(activerecord activesupport)
|
15
|
+
end
|
16
|
+
rescue LoadError => boom
|
17
|
+
puts "You are missing a dependency required for meta-operations on this gem."
|
18
|
+
puts "#{boom.to_s.capitalize}."
|
15
19
|
end
|
@@ -7,7 +7,7 @@ module Searchlogic
|
|
7
7
|
class Base
|
8
8
|
include Shared::Utilities
|
9
9
|
|
10
|
-
attr_accessor :column, :column_for_type_cast, :column_sql, :column_sql_format, :klass, :table_name
|
10
|
+
attr_accessor :any, :column, :column_for_type_cast, :column_sql, :column_sql_format, :klass, :object_name, :table_name
|
11
11
|
class_inheritable_accessor :handle_array_value, :ignore_meaningless_value, :join_arrays_with_or, :value_type
|
12
12
|
self.ignore_meaningless_value = true
|
13
13
|
|
@@ -61,6 +61,10 @@ module Searchlogic
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
+
def any? # :nodoc:
|
65
|
+
any == true
|
66
|
+
end
|
67
|
+
|
64
68
|
# 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.
|
65
69
|
# 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.
|
66
70
|
def column_sql
|
@@ -5,7 +5,7 @@ module Searchlogic
|
|
5
5
|
self.join_arrays_with_or = true
|
6
6
|
|
7
7
|
BLACKLISTED_WORDS = ('a'..'z').to_a + ["about", "an", "are", "as", "at", "be", "by", "com", "de", "en", "for", "from", "how", "in", "is", "it", "la", "of", "on", "or", "that", "the", "the", "this", "to", "und", "was", "what", "when", "where", "who", "will", "with", "www"] # from ranks.nl
|
8
|
-
|
8
|
+
ALLOWED_CHARACTERS = 'àáâãäåßéèêëìíîïñòóôõöùúûüýÿ\-_\.@'
|
9
9
|
|
10
10
|
class << self
|
11
11
|
def condition_names_for_column
|
@@ -35,7 +35,7 @@ module Searchlogic
|
|
35
35
|
def replace_non_alnum_characters!(search_parts)
|
36
36
|
search_parts.each do |word|
|
37
37
|
word.downcase!
|
38
|
-
word.gsub!(/[^[:alnum:]#{
|
38
|
+
word.gsub!(/[^[:alnum:]#{ALLOWED_CHARACTERS}]/, '')
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Searchlogic
|
2
|
+
module Conditions
|
3
|
+
# = Any or All
|
4
|
+
#
|
5
|
+
# Adds the ability to join all conditions wth "ANY" or "ALL".
|
6
|
+
module AnyOrAll
|
7
|
+
# Determines if we should join the conditions with "AND" or "OR".
|
8
|
+
#
|
9
|
+
# === Examples
|
10
|
+
#
|
11
|
+
# search.conditions.any = true # will join all conditions with "or", you can also set this to "true", "1", or "yes"
|
12
|
+
# search.conditions.any = false # will join all conditions with "and"
|
13
|
+
def any=(value)
|
14
|
+
objects.each { |object| object.any = value }
|
15
|
+
@any = value
|
16
|
+
end
|
17
|
+
|
18
|
+
def any # :nodoc:
|
19
|
+
any?
|
20
|
+
end
|
21
|
+
|
22
|
+
# Convenience method for determining if we should join the conditions with "AND" or "OR".
|
23
|
+
def any?
|
24
|
+
["true", "1", "yes"].include? @any.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
# Sets the conditions to be searched by "or"
|
28
|
+
def any!
|
29
|
+
self.any = true
|
30
|
+
end
|
31
|
+
|
32
|
+
def all? # :nodoc:
|
33
|
+
!any?
|
34
|
+
end
|
35
|
+
|
36
|
+
# Sets the conditions to be searched by "and"
|
37
|
+
def all!
|
38
|
+
self.any = false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|